直播型网站开发,12306网站建设 实际,深圳品牌设计公司排行榜,wordpress更改网站信息1.profile与bean
1.1 profile
如果我们在配置类中装配一个bean#xff0c;但是这个bean与环境相关怎么办#xff1f;
比如有一个类#xff0c;它在开发环境采取一种模式#xff0c;但是到了生产环境#xff0c;有需要使用另一种环境。
当然#xff0c;你可能会说但是这个bean与环境相关怎么办
比如有一个类它在开发环境采取一种模式但是到了生产环境有需要使用另一种环境。
当然你可能会说写两个类。但是实际情况可能不允许。这个时候需要根据环境的不同生产不同的bean。它使用的方法是Profile
举一个例子 Configuration Profile(dev) public class DevProfileConfig{ Bean public A a{...} Bean public B b{...} } 只有在dev环境中这个配置类下面的bean才能生成
Profile不仅仅可以用在类上也可用在方法中代表这个类只有满足环境要求才能生产bean Configuration public class DevProfileConfig{ Bean Profile(dev1) public A a{...} Bean Profile(dev2) public B b{...} Bean public B b{...} } 我觉得不需要我解释上面的含义了。
但是需要注意。其他的bean指的是同一个类如果其他bean没用指定相同的profile环境那么这样的bean依然会生成。
同样xml文件也能实现这里就略过xml文件的讲解吧都是一个逻辑。
1.2 激活profile
上面讲了profile掌握bean的生产条件它与profile的环境相关。只要profile被激活比如成为dev环境那么相应的bean就会生效。如何让它激活
它依赖于两个独立的属性
(1).java.profile.active
(2).java.profile.default
它先查看active的值如果处于激活状态则取它的值反之则取default但是如果两个都没有激活则profile控制的bean都无法生成。
那么如何设置这两个属性呢
有很多办法。
其中常用的有
作为DispatcherServlet的初始化参数
作为web应用的上下文
作为环境变量
作为JVM的系统属性
在集成测试类上使用ActiveProfile注解设置
还要其他很多根据情况设置即可
2.条件化的bean
2.1 Conditional
Conditional
当满足某个条件的时候该bean才会被创建。这种条件可能是某个库是否存在其他某个bean是否被创建某个特定的环境变量是否为特定的值。。。。。。
Bean
Conditional(MagicExistsCondition.class)
public MagicBean magicBean(){return new MagicBean();
}
上面的代码片段应该写在某个配置类中。它通过检查MagicExistsCondition这个类是否存在来决定要不要创建MagicBean。
它是通过Conditional这个接口实现来判断的接口为
public interface Conditional{boolean matches(Conditional ctxt, AnnotatedTypeMetadata metadata);
}
显式这个接口的类只需要实现它的matches方法即可如果返回true则代表条件满足下面创建这个类来实现这个接口以供条件判断
package com.example.demo.conditional;import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;public class MagicExistsConditional implements Condition {Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {Environment env context.getEnvironment();return env.containsProperty(magic);}
}
通过ConditionContext类获取环境类然后判断环境中有没有这个magic属性。
如果这么写肯定是返回false的因为环境变量里面确实没有这个属性。
了解一下传入的两个参数很有必要
2.2 ConditionContext类和AnnotatedTypeMetadata类
ConditionContext类定义如下它是一个接口我们可以叫他条件上下文。 public interface ConditionContext {BeanDefinitionRegistry getRegistry();NullableConfigurableListableBeanFactory getBeanFactory();Environment getEnvironment();ResourceLoader getResourceLoader();NullableClassLoader getClassLoader();
} getRegistry()返回的BeanDefinitionRegistry可以检查bean的定义。
getBeanFactory()返回的ConfigurableListableBeanFactory可以检查bean是否存在。
getEnvironment()返回的Environment可以检查环境变量属性以及值。
getResourceLoader()返回ResourceLoader可以读取加载的资源。
getClassLoader()返回ClassLoader可以判断类是否存在。
AnnotatedTypeMetadata接口如下 public interface AnnotatedTypeMetadata {MergedAnnotations getAnnotations();default boolean isAnnotated(String annotationName) {return this.getAnnotations().isPresent(annotationName);}Nullabledefault MapString, Object getAnnotationAttributes(String annotationName) {return this.getAnnotationAttributes(annotationName, false);}Nullabledefault MapString, Object getAnnotationAttributes(String annotationName, boolean classValuesAsString) {MergedAnnotationAnnotation annotation this.getAnnotations().get(annotationName, (Predicate)null, MergedAnnotationSelectors.firstDirectlyDeclared());return !annotation.isPresent() ? null : annotation.asAnnotationAttributes(Adapt.values(classValuesAsString, true));}Nullabledefault MultiValueMapString, Object getAllAnnotationAttributes(String annotationName) {return this.getAllAnnotationAttributes(annotationName, false);}Nullabledefault MultiValueMapString, Object getAllAnnotationAttributes(String annotationName, boolean classValuesAsString) {MergedAnnotation.Adapt[] adaptations Adapt.values(classValuesAsString, true);return (MultiValueMap)this.getAnnotations().stream(annotationName).filter(MergedAnnotationPredicates.unique(MergedAnnotation::getMetaTypes)).map(MergedAnnotation::withNonMergedAttributes).collect(MergedAnnotationCollectors.toMultiValueMap((map) - {return map.isEmpty() ? null : map;}, adaptations));}
}这个接口显然都是检查注解的属性。就不详细解说了。
3. 处理自动装配的歧义性
3.1 Qualifier
如果很多类都继承了同一个接口且都完成了bean的定义那么在自动装配的时候应该选哪个bean?比如下面这段代码
//公共接口
public interface BaseClass{}
//下面三个类全都实现了公告接口Component
public class OneClass implements BaseClass{}Component
public class TwoClass implements BaseClass{}Component
public class ThreeClass implements BaseClass{}//自动装配选择哪一个
public class Test{Autowiredprivate BaseClass b;
}解决这个问题可以用以下几个方法
(1)Primary
在Bean下面注解表示出现歧义的时候优先使用这个bean。但是同类型的只能在其中一个上使用。
(2)Qualifier
它可以指定某一个bean Autowired Qualifier(id) public void setData(BaseClass data){......} 这就相当于指定一个bean进行导入这个bean的id是id
如果没有显式写id一般bean的id就是类名的首字母小写比如Oneclass的id就是oneClass
值得一提的是id和类名紧耦合在一起可不是什么好事因为变更以下名字代码就需要修改了不如直接给它限定一个id
比如 Component Qualifier(one) public class OneClass{......} 这样OneClass的bean id就一直都是one了通过这个名字可以索引到bean
如果相要写一个单元测试就需要添加一个配置类作为管理这三个bean的类。
3.2 自定义限定符
比如出现了一个大类都是数字类但是下面又有了具体的One,Two,Three这样的小类而我们想要有一个层次的限定符呢
首先所有的数字类都可以使用Qualifier(number)进行限定
其次为了对number下的各个小类进行限定 Target({ElementType.CONSTRUCTOR, ElementType.FIFLD, ElementType.METHOD, ElementType.TYPE}) Retention(RetentionPollicy.RUNTIME) Qualifier publlic interface Number() 上面的代码表示新建了一个Number注解下面就可以使用Number注解了。
然后Number注解可以缩小注解范围 Number Qualifier(oneClass) 这代表限制对象的了两层限制。
4.bean的作用域
bean一般情况下是单例模式但是它可以选择其他模型比如
1单例模式每次都导入的都是同一个bean
2原型模式每次创建的都是不同的bean
3会话模式为每个会话创建一个bean
4请求模式为每个请求创建一个bean
想要修改bean的模式可以使用Scope注解比如修改bean的模式是原型模式
Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
xml文件也差不多这样
这里不详细解释只是简单说一下。
比如在购物时每一个人都会有一个购物服务每一个服务都需要一个购物车那么我们希望服务每次都是新的但是购物车都是同一个不然每一次访问服务都创建一个新购物车我们岂不是要到处翻上一次添加的购物记录吗所有才会有会话的作用域。
5. 运行时值注入
我们希望在bean能够在运行时给自己的成员赋值该如何做
虽然之前提到在类里面配置或者在xml种配置但是这些值其实都是固定的没办法更改。我们怎么在代码运行时让它自己去设置呢
5.1 注入外部的值
在spring中最简单的方法就是使用Environment来检索属性
比如在app.properties写入下面的代码
data.titletitle
data.artist artist
有一个类
public class BlackDisc implements CompactDisc{private String title;private String artist;public BlackDisc(String title, String artist) {this.title title;this.artist artist;}public void setTitle(String title) {this.title title;}public void setArtist(String artist) {this.artist artist;}Overridepublic void play() {System.out.println(Playing title by artist);}}通过配置类读取app.properties
import com.example.demo.project.BlackDisc;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;Configuration
PropertySource(classpath:app.properties)
public class Load {AutowiredEnvironment env;Beanpublic BlackDisc blackDisc(){return new BlackDisc(env.getProperty(data.title),env.getProperty(data.artist));}
}测试输出
package com.example.demo.environment;import com.example.demo.autoSelectBean.BaseClass;
import com.example.demo.project.BlackDisc;
import com.example.demo.project.CDConfig;
import com.example.demo.project.CDPlayerConfig;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;RunWith(SpringJUnit4ClassRunner.class)
ContextConfiguration(classes {Load.class})
public class Test3 {Autowiredprivate BlackDisc blackDisc;Testpublic void test() {blackDisc.play();}
}总结app.properties的信息会被Environment读取我们可以使用getProperty来获取参数值
getProperty有多个重载 Nullable
String getProperty(String key);//返回字符串String getProperty(String key, String defaultValue);//返回字符串但是如果key不存在则返回默认值Nullable
T T getProperty(String key, ClassT targetType);//可以返回指定的类型T T getProperty(String key, ClassT targetType, T defaultValue);//可以返回指定的类型如果key不存在则返回默认值 因为我们的配置文件不一定都是String也有可能是其他的类型。
Environment类还提供了其他的方法 boolean containsProperty(String key);//判断是否包含key String getRequiredProperty(String key) throws IllegalStateException;//直接获取key对应的值返回类型为String,但是如果key对应的值不存在则抛出错误T T getRequiredProperty(String key, ClassT targetType) throws IllegalStateException;//返回为指定类型5.2 通过占位符获取属性值
也就是用${}
Configuration
PropertySource(classpath:app.properties)
public class Load {AutowiredEnvironment env;Value(${data.title})String title;Value(${data.artist})String artist;Beanpublic BlackDisc blackDisc(){return new BlackDisc(title , artist );}
}
比如上面的代码就是从app文本中导入数据
5.3 使用Spring表达式语言进行装配
这里不做详细介绍因为没有必要。在做web开发时这东西到处都是。只需要看原理和几个案例。
Spring 表达式有很多特性它可以通过下面的方法导入
1使用bean的id引用bean
2调用方法和访问对象属性
3对值进行运算
4正则表达式匹配
5集合操作
Spring表达式需要使用#{}也就是表达式要放在里面
比如通过某个类的方法 Value(#{bean.getNumber()}) Integer number;