【每天学点Spring】

【每天学点Spring】@ConditionalOnProper

2022-04-18  本文已影响0人  伊丽莎白2015

@ConditionalOnProperty是Springboot的注解。是spring-boot-autoconfigure包里的注解,从Spring boot v1.1.0就开始就了。

当我们创建bean的时候,有时候需要根据不同的property的值来创建不同的bean,比如property值=dev或者prod。这时候就需要使用@ConditionalOnProperty注解了,它可以在某些环境变量存在的时候并且等于特定值的时候,才去创建某个bean。

@ConditionalOnProperty有5个变量,分别是value, prefix, name, havingValue和matchIfMissing:


ConditionalOnProperty.jpg

1. 简单demo

@Service(value = "simpleCacheService")
@ConditionalOnProperty(prefix = "conditional.cache", name = "type")
public class SimpleCacheServiceImpl implements CacheService {
    public void init() {}
}

在application.properties里配置:

conditional.cache.type=simple

测试SimpleCacheServiceImpl有没有被加载:

@SpringBootTest
public class SimpleCacheServiceTest {
    @Autowired
    private CacheService simpleCacheService;

    @Test
    public void initTest() {
       Assertions.assertTrue(simpleCacheService.getClass().getName().contains("SimpleCacheService"));
    }
}

如果不配置conditional.cache.type,那么simpleCacheService注入不了。
上述@ConditionalOnProperty(prefix = "conditional.cache", name = "type")配置的意思是当有profix.name配置存在的时候,即可加载该Bean。

2. 高级用法

@Service(value = "redisCacheService")
@ConditionalOnProperty(prefix = "conditional.cache", value = "type", havingValue = "redis")
public class RedisCacheServiceImpl implements CacheService {
    public void init() {}
}

测试通过:

@SpringBootTest
public class RedisCacheServiceTest {
    private final ApplicationContextRunner contextRunner = new ApplicationContextRunner();

    @Test
    public void initTest() {
        this.contextRunner.withPropertyValues("conditional.cache.type=redis")
                .withUserConfiguration(RedisCacheServiceImpl.class)
                .run(context -> {
            CacheService redisCacheService = (CacheService) context.getBean("redisCacheService");
            Assertions.assertTrue(redisCacheService.getClass().getName().contains("RedisCacheService"));
        });
    }

}

加了havingValue="redis",意味着有如下配置并且值等于redis时,才会加载redisCacheService:

conditional.cache.type=redis

3. Spring源码中的@ConditionalOnProperty

@Configuration(proxyBeanMethods = false)
    @ConditionalOnWebApplication(type = Type.SERVLET)
    @ConditionalOnClass(WebMvcConfigurer.class)
    @ConditionalOnMissingBean({ OpenEntityManagerInViewInterceptor.class, OpenEntityManagerInViewFilter.class })
    @ConditionalOnMissingFilterBean(OpenEntityManagerInViewFilter.class)
    @ConditionalOnProperty(prefix = "spring.jpa", name = "open-in-view", havingValue = "true", matchIfMissing = true)
    protected static class JpaWebConfiguration {
        // 略
}

先别管别的Conditional注解,看最后一个:
matchIfMissing=true,意思是,不配置spring.jpa.open-in-view也会加载Bean,但如果有配置,那么需要配置:spring.jpa.open-in-view=true
反过来说,如何不加载这个Bean:spring.jpa.open-in-view=false

4. 最后放下源码:

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
@Conditional(OnPropertyCondition.class)
public @interface ConditionalOnProperty {
    // 同name
    String[] value() default {};
    // 前缀,如:acme.system.feature
    String prefix() default "";
    // 与prefix协同使用:
    String[] name() default {};
    // property里应该配的值,如果相等,则表示激活该bean
    String havingValue() default "";
    // 默认不配置就不激活该bean
    boolean matchIfMissing() default false;
}

【参考】
Spring conditionalOnProperty: https://www.baeldung.com/spring-conditionalonproperty
Spring Boot ApplicationContextRunner 测试指南: https://blog.csdn.net/j3T9Z7H/article/details/94365999

上一篇下一篇

猜你喜欢

热点阅读