Spring3开始提供的profile机制用起来的确很爽,在Spring4中提供了一种更通用的条件化Bean定义机制。
@Conditional注解
使用@Conditional注解
定义一个Bean,这个Bean只有在满足MagicExistCondition中定义的条件时才会创建。
| 12
 3
 4
 5
 
 | @Bean@Conditional(MagicExistCondition.class)
 public MagicBean magicBean() {
 return new MagicBean();
 }
 
 | 
这里的@Conditional注解定义如下:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | @Target({ElementType.TYPE, ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)
 @Documented
 public @interface Conditional {
 
 
 
 
 Class<? extends Condition>[] value();
 
 }
 
 
 | 
实现Condition接口
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | public class MagicExistCondition implements Condition {
 
 
 
 public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
 Environment env = context.getEnvironment();
 
 return env.containsProperty("magic");
 }
 
 }
 
 | 
这里的matches方法有两个参数,分别为ConditionContext,AnnotatedTypeMetadata类型
ConditionContext
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 
 | 
 
 
 public interface ConditionContext {
 
 
 
 
 BeanDefinitionRegistry getRegistry();
 
 
 
 
 ConfigurableListableBeanFactory getBeanFactory();
 
 
 
 
 Environment getEnvironment();
 
 
 
 
 ResourceLoader getResourceLoader();
 
 
 
 
 ClassLoader getClassLoader();
 
 }
 
 | 
AnnotatedTypeMetadata
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 
 | public interface AnnotatedTypeMetadata {
 
 
 
 boolean isAnnotated(String annotationName);
 
 
 
 
 
 
 Map<String, Object> getAnnotationAttributes(String annotationName);
 
 
 
 
 Map<String, Object> getAnnotationAttributes(String annotationName, boolean classValuesAsString);
 MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName);
 MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName, boolean classValuesAsString);
 
 }
 
 | 
Spring4对@Profile注解进行的重构
从Spring4开始,@Profile注解使用@Conditional注解实现。我们可以以它为例,学习如何使用@Conditional注解。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | 
 
 @Target({ElementType.TYPE, ElementType.METHOD})
 @Retention(RetentionPolicy.RUNTIME)
 @Documented
 
 @Conditional(ProfileCondition.class)
 public @interface Profile {
 String[] value();
 }
 
 | 
可以看以下ProfileCondition的实现
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 
 | 
 
 class ProfileCondition implements Condition {
 
 @Override
 public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
 if (context.getEnvironment() != null) {
 
 MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
 if (attrs != null) {
 
 for (Object value : attrs.get("value")) {
 
 if (context.getEnvironment().acceptsProfiles(((String[]) value))) {
 return true;
 }
 }
 return false;
 }
 }
 return true;
 }
 
 }
 
 | 
SpringBoot自动化配置中的Condition
Spring中的自动化配置基本就是靠这个@Condition注解实现的,所以在springboot-autoconfig中有一大堆实现了Condition接口的类:

另外SpringBoot还提供了很多类似于@Profile的注解:

如果有机会再后续的文章中会对SpringBoot的自动化配置进行详细分析。
参考:
Spring In Action
Spring Framework Documentation