Skip to content

Latest commit

 

History

History
144 lines (107 loc) · 4.7 KB

自定义conditional.md

File metadata and controls

144 lines (107 loc) · 4.7 KB

什么是Conditional

conditionspring提供的一个特性,用于在初始化对象时对初始化条件进行检测,满足条件的对象才予以创建。

SpringBoot提供了ConditionalOnBeanConditionalOnClassConditionalOnProperty等。分别用于不同的场景下对bean对象的创建行为进行限制。

如何自定义Conditional

1、创建自定义的注解

@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方法来判断是否要创建对象。

2、创建Condition的实现类。

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, "");
    }
}

3、注意事项

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