condition
是spring
提供的一个特性,用于在初始化对象时对初始化条件进行检测,满足条件的对象才予以创建。
SpringBoot
提供了ConditionalOnBean
、ConditionalOnClass
、ConditionalOnProperty
等。分别用于不同的场景下对bean
对象的创建行为进行限制。
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(MyCondition.class)
public @interface MyConditionAnnotation {
String value() default "";
}
通过创建自定义的注解,并且使用Conditional
注解在我们自定义的注解上面。Conditional
需要传递一个实现了org.springframework.context.annotation.Condition
的类。spring
会通过调用该实现类的matches
方法来判断是否要创建对象。
在SpringBoot
中,我们可以通过继承org.springframework.boot.autoconfigure.condition.SpringBootCondition
类,并重写getMatchOutcome
方法进行实现。
getMatchOutcome
需要返回一个ConditionOutcome
对象,我们可以通过new ConditionOutcome(bool,desc)
来创建该对象,构造器中需要接受两个参数,第一个为当前匹配是否成功,第二个为描述。当我们检测到当前环境满足Bean的初始化条件,就需要将第一个参数设为true
。
创建匹配类
public class MyCondition extends SpringBootCondition {
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 处理逻辑
return new ConditionOutcome(true, "");
}
}
1、在匹配类中可能无法自动注入bean
由于Conditional
用于标注当前环境是否满足bean
的创建条件,所以通过context.getBeanFactory().getBean("name")
可能无法获取到希望的对象,因为这里查询的对象可能还没有被初始化。
2、不能通过自动注入配置的类来获取配置参数值。
就如上面解释的。在匹配类被调用时,对象可能没有被初始化,所以当我们直接访问配置类时,可能获取不到正确的配置。
解决方式是使用PropertyResolver
进行获取指定属性。
PropertyResolver resolver = context.getEnvironment();
String property = resolver.getProperty("属性名");
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnEnvironmentConditional.class)
public @interface ConditionalOnEnvironment {
/**
* 当前条件支持的环境列表
*/
Environment[] value() default Environment.PRODUCT;
}
public enum Environment {
/**
* 开发环境
*/
DEVELOP,
/**
* 测试环境
*/
TEST,
/**
* 生产环境
*/
PRODUCT
}
public class OnEnvironmentConditional extends SpringBootCondition {
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
PropertyResolver resolver = context.getEnvironment();
String property = resolver.getProperty("business.environment", Environment.PRODUCT.name());
Environment environment = Environment.valueOf(property.toUpperCase());
if (metadata.isAnnotated(ConditionalOnEnvironment.class.getName())) {
Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(ConditionalOnEnvironment.class.getName());
Environment[] envs = (Environment[]) annotationAttributes.get("value");
List<Environment> envList = Arrays.asList(envs);
if (envList.contains(environment)) {
return new ConditionOutcome(true, "环境检查通过");
}
return new ConditionOutcome(false, "环境检查未通过");
}
return new ConditionOutcome(true, "no ConditionalOnEnvironment marked");
}
}
@Bean
@ConditionalOnEnvironment({Environment.DEVELOP, Environment.TEST})
public FilterRegistrationBean<AllowOriginFilter> allowOriginFilter() {
FilterRegistrationBean<AllowOriginFilter> bean = new FilterRegistrationBean<>();
bean.setFilter(new AllowOriginFilter());
bean.addUrlPatterns("/*");
bean.setName("AllowOriginFilter");
bean.setOrder(1);
return bean;
}
business.environment = develop