高级装配
配置profile bean
spring为环境相关的bean提供的解决方案其实与构建时的方案没有太大区别,根据环境决定该创建那个bean和不该创建哪个bean,且这并不是在构建时决定的,而是等到运行时来确定,使同一个部署单元能够适用于所有环境
profile 的Java代码配置
使用@Profile注解指定某个bean属于哪一个profile
如
@Configuration
@Profile("dev")
public class ProfileConfig{
@Bean
public DataSource dataSource(){
return new ...;
}
}
上面的@Profile注解用在了类级别上,表明,这个配置类中的bean只有在 dev profile 激活
时才会创建,否则带有@Bean注解的方法都会被忽略掉
--------------------------
从spring3.2开始还可以在方法级别上使用@Profile注解,
方便将不同环境对应的bean放在同一个配置类中
@Configuration
public class ProfileConfig{
@Bean
@Profile("dev")
public DataSource dataSource(){
return new ....;
}
}
没有指定profile的bean始终都会被创建,与激活那个profile无关。
在xml中配置profile
通过元素的profile属性配置
<beans xmlns=.......
profile="dev" >
<bean .../>
...
</beans>
还可以在根<beans>元素中嵌套定义<beans>元素,方便将不
同环境的配置放到同一个xml文件中
<beans xmlns=....... >
<beans profile="qa">
<bean ... />
</beans>
...
</beans>
激活 profile
spring通过两个独立的属性:
- spring.profiles.active
- spring.profiles.default
来确定哪个profile处于激活状态
设置了active属性的话,就会根据他的值确定哪个profile是激活的,否则就会查找default的值,active和default均没有设置的话,那就没有激活的profile
可同时设置多种profile值用逗号分隔设置这两个属性的方式
- 作为DispatcherServlet的初始化参数
- 作为Web应用的上下文参数
- 作为JNDI条目
- 作为环境变量
- 作为JVM的系统属性
- 在集成测试类上,使用@ActiveProfiles注解设置
在Web应用的web.xml文件中设置默认的profile
<web-app ..... >
<context-param>//为上下文设置默认的profile
<param-name>spring.profiles.default</param-name>
<param-value>dev</param-value>
</context-param>
<servlet>
...
<init-param>//为servlet设置默认的profile
<param-name>spring.profiles.default</param-name>
<param-value>dev</param-value>
</init-param>
...
</servlet>
按条件配置bean
应用场景:例如希望一个或多个bean只有在应用的类路径下包含特定的库时才创建,或希望某个bean只有在另外某个特定的bean也声明了之后才创建
spring 引入的新的注解 @Conditional ,他可以用到带有@Bean注解的方法上,如果给定的计算结果为true就会创建这个bean,否则这个bean会被忽略
假设有一个MagicBean的类,我们希望只有设置了magic环境属性的时候spring才会实例化这个类
@Bean
@Conditional(MagicExistsCondition.class)
public MagicBean magicBean(){
return new MagicBean();
}
@Conditional 会通过Condition接口进行条件对比
public interface Condition{
boolean matches(ConditionContext ctxt,AnnotatedTypeMetadata metadata);
}
设置给@Conditional的类可以是任意实现了Condition接口的类型
public class MagicExistsCondition implements Condition{
public boolean matches(ConditionContext context,AnnotatedTypeMetadata metadata){
Environment env = context.getEnvironment();
return env.containsProperty("magic");
}
}
------------------------
ConditionContext 是一个接口 大致如下
public ConditionContext{
BeanDefinitionRegistry getRegistry(); //通过返回值检查bean的定义
ConfigurableListableBeanFactory getBeanFactory(); //通过返回值检查bean是否存在,甚至探查bean属性
Environment getEnvironment();//返回的Environment检查环境变量是否存在以及它的值是什么
ResourceLoader getResourceLoader();//读取并探查返回的ResourceLoader所加载的资源
ClassLoader getClassLoader();//借助返回的对象加载并检查类是否存在
}
AnnotatedTypeMetadata 则能让我们检查带有@Bean注解的方法上还有什么其他的注解,它也是一个接口
@Profile 本身也使用了 @Conditional注解