假设你希望某个 bean 只有在满足某个条件的时候才会创建,Spring 4 引入了一个新的 @Conditional 注解,它可以用到带有 @Bean 注解的方法上,如果给定的条件结果为 true,则创建这个 bean,否则,这个 bean 会被忽略。
以下是一个示例:
@Bean
@Conditional(MagicExistsCondition.class)
public MagicBean magicBean(){
return new MagicBean();
}
注意到,magicBean 方法被 @Conditional 注解修饰,值为 MagicExistsCondition.class。
MagicExistsCondition.class:
public class MagicExistsCondition implements Condition{
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata){
Environment env = context.getEnvironment();
return env.containsProperty("magic"); //检查Magic属性
}
}
作为 @Conditional 注解的值的类必须实现 Condition 接口,Condition 接口只有一个返回类型为 boolean 的 matches() 方法,Spring 将根据 matches() 方法的返回值来决定是否创建 bean,在上例中,matches() 方法检查环境中是否存在名为 magic 的环境属性,属性的值是什么无所谓,只要存在这个属性,matches() 方法就会返回 true,所带来的结果就是条件能够得到满足,所有 @Conditional 注解上引用 MagicExistsCondition 的 bean 都会被创建。
Condition 接口:
public interface Condition{
boolean matches(ConditionContext ctxt, AnnotatedTypeMetadata metadata);
}
matches() 方法通过 ConditionContext 和 AnnotatedTypeMetadata 来做出决策。
ConditionContext 接口:
public interface ConditionContext{
BeanDefinitionRegistry getRegistry();
ConfigurableListableBeanFactory getBeanFactory();
Environment getEnvironment();
ResourceLoader getResourceLoader();
ClassLoader getClassLoader();
}
通过 ConditionContext 接口,我们可以做到如下几点:
- 借助 getRegistry() 返回的 BeanDefinitionRegistry 检查 bean 定义;
- 借助 getBeanFactory() 返回的 ConfifurableListableBeanFactory 检查 bean 是否存在,甚至探查 bean 的属性;
- 借助 getEnvironment() 返回的 Environment 检查环境变量是否存在以及它的值是什么;
- 读取并探查 getResourceLoader() 返回的 ResourceLoader 所加载的资源;
- 借助 getClassLoader() 返回的 ClassLoader 加载并检查类知否存在;
AnnotatedTypeMetadata接口:
public interface AnnotatedTypeMetadata{
boolean isAnnotated(String annotationType);
Map<String, Object> getAnnotationAttributes(String annotationType);
Map<String, Object> getAnnotationAttributes(String annotationType, boolean classValuesAsString);
MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationType);
MultiValueMap<String, Object> getAllAnnotationAttrubutes(String annotationType, boolean classValuesAsString);
}
- 借助 isAnnotated() 方法,我们能够判断带有 @Bean 注解的方法是不是还带有其他特定的注解
- 借助其他的方法,我们能够检查 @Bean 注解的方法上其他注解的属性。