• Spring Boot框架中的@Conditional系列注解


    目录

    1. @Conditional 注解

    2. Spring boot 扩展

    1) @ConditionalOnClass和@ConditionalOnMissingClass注解

    2) @ConditionalOnBean 和@ConditionalOnMissingBean注解

    3) @ConditionalOnProperty注解


    1. @Conditional 注解

            @Conditional注解是Spring-context模块提供了一个注解,该注解的作用是可以根据一定的条件来使@Configuration注解标记的配置类是否生效,代码如下:

    1. //
    2. // Source code recreated from a .class file by IntelliJ IDEA
    3. // (powered by FernFlower decompiler)
    4. //
    5. package org.springframework.context.annotation;
    6. import java.lang.annotation.Documented;
    7. import java.lang.annotation.ElementType;
    8. import java.lang.annotation.Retention;
    9. import java.lang.annotation.RetentionPolicy;
    10. import java.lang.annotation.Target;
    11. @Target({ElementType.TYPE, ElementType.METHOD})
    12. @Retention(RetentionPolicy.RUNTIME)
    13. @Documented
    14. public @interface Conditional {
    15. Classextends Condition>[] value();
    16. }

            value值为实现Condition 接口的一个Class,Spring框架根据实现Conditon接口的matches方法返回true或者false来做以下操作,如果matches方法返回true,那么该配置类会被Spring扫描到容器里, 如果为false,那么Spring框架会自动跳过该配置类不进行扫描装配,使用方法:

            实现Condition接口, 例如在配置文件里配置了dataSource.none=true, 那么表示不需要使用数据源,那么Spring在扫描的时候会自动跳过该配置类。

    1. package com.bing.sh.datasource;
    2. import org.springframework.context.annotation.Condition;
    3. import org.springframework.context.annotation.ConditionContext;
    4. import org.springframework.core.type.AnnotatedTypeMetadata;
    5. /**
    6. * 如果为返回false,那么Spring会忽略配置类
    7. */
    8. public class DataSourceCondition implements Condition {
    9. @Override
    10. public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
    11. // 此处使用 conditionContext获取Environment即可。
    12. String configureDataSource = conditionContext.getEnvironment().getProperty("dataSource.none", "false");
    13. return "false".equals(configureDataSource);
    14. }
    15. }

            定义配置类,与@Conditional注解一起使用:

    1. @Configuration
    2. @Conditional(value = DataSourceCondition.class)
    3. public class CustomDataSourceConfig {
    4. }

            除了Conditional注解,Spring boot 框架提供了 其他conditional系列注解。

    2. Spring boot 扩展

            SpringBoot的spring-boot-autoconfigure模块也提供了Conditional系列的相关注解,这些注解能帮助开发者根据一定的条件去装载需要的Bean。 

    1) @ConditionalOnClass和@ConditionalOnMissingClass注解

            当Spring加载的Bean被@ConditionOnClass注解标记时,类加载器会先去先找到指定的Class, 如果没有找到目标Class,那么被ConditionOnClass注解标记的类不会被Spring装载,相反ConditionalOnMissingBean是指如果没有找到目标Class, 那么就装载该类。

    2) @ConditionalOnBean 和@ConditionalOnMissingBean注解

            当Spring加载的Bean被@ConditionalOnBean注解标记时,接下来会先找到指定的Bean,如果没有找到目标Bean,那么被@ConditionalOnBean标记的类不会被Spring装载,相反ConditionalOnMissingBean是指如果没有Class, 那么就装载该Bean。

            看一个例子, Dubbo与Springboot做自动装配时,先寻找BASE_PACKAGES_BEAN_NAME这个Bean, 如果Bean 不存在,那么serviceAnnotationBeanProcessor这个Bean不会被Spring 装载.

    1. @ConditionalOnProperty(prefix = DUBBO_PREFIX, name = "enabled", matchIfMissing = true)
    2. @Configuration
    3. @AutoConfigureAfter(DubboRelaxedBindingAutoConfiguration.class)
    4. @EnableConfigurationProperties(DubboConfigurationProperties.class)
    5. @EnableDubboConfig
    6. public class DubboAutoConfiguration {
    7. /**
    8. * Creates {@link ServiceAnnotationPostProcessor} Bean
    9. * dubbo.scan.base-packages
    10. * @param packagesToScan the packages to scan
    11. * @return {@link ServiceAnnotationPostProcessor}
    12. */
    13. @ConditionalOnProperty(prefix = DUBBO_SCAN_PREFIX, name = BASE_PACKAGES_PROPERTY_NAME)
    14. // 先找BASE_PACKAGES_BEAN_NAME 这个bean, 如果没有这个bean, 那么serviceAnnotationBeanProcessor不会被Spring装载。
    15. @ConditionalOnBean(name = BASE_PACKAGES_BEAN_NAME)
    16. @Bean
    17. public ServiceAnnotationPostProcessor serviceAnnotationBeanProcessor(@Qualifier(BASE_PACKAGES_BEAN_NAME)
    18. Set packagesToScan) {
    19. return new ServiceAnnotationPostProcessor(packagesToScan);
    20. }
    21. }

            使用@ConditionalOnMissingBean注解定义BASE_PACKAGES_BEAN_NAME这个Bean

    1. /**
    2. * Dubbo Relaxed Binding Auto-{@link Configuration} for Spring Boot 2.0
    3. *
    4. * @see DubboRelaxedBindingAutoConfiguration
    5. * @since 2.7.0
    6. */
    7. @Configuration
    8. @ConditionalOnProperty(prefix = DUBBO_PREFIX, name = "enabled", matchIfMissing = true)
    9. @ConditionalOnClass(name = "org.springframework.boot.context.properties.bind.Binder")
    10. @AutoConfigureBefore(DubboRelaxedBindingAutoConfiguration.class)
    11. public class DubboRelaxedBinding2AutoConfiguration {
    12. public PropertyResolver dubboScanBasePackagesPropertyResolver(ConfigurableEnvironment environment) {
    13. ConfigurableEnvironment propertyResolver = new AbstractEnvironment() {
    14. @Override
    15. protected void customizePropertySources(MutablePropertySources propertySources) {
    16. Map dubboScanProperties = getSubProperties(environment.getPropertySources(), DUBBO_SCAN_PREFIX);
    17. propertySources.addLast(new MapPropertySource("dubboScanProperties", dubboScanProperties));
    18. }
    19. };
    20. ConfigurationPropertySources.attach(propertyResolver);
    21. return propertyResolver;
    22. }
    23. /**
    24. * The bean is used to scan the packages of Dubbo Service classes
    25. * 如果没有就创建
    26. * @param environment {@link Environment} instance
    27. * @return non-null {@link Set}
    28. * @since 2.7.8
    29. */
    30. @ConditionalOnMissingBean(name = BASE_PACKAGES_BEAN_NAME)
    31. @Bean(name = BASE_PACKAGES_BEAN_NAME)
    32. public Set dubboBasePackages(ConfigurableEnvironment environment) {
    33. PropertyResolver propertyResolver = dubboScanBasePackagesPropertyResolver(environment);
    34. return propertyResolver.getProperty(BASE_PACKAGES_PROPERTY_NAME, Set.class, emptySet());
    35. }
    36. @ConditionalOnMissingBean(name = RELAXED_DUBBO_CONFIG_BINDER_BEAN_NAME, value = ConfigurationBeanBinder.class)
    37. @Bean(RELAXED_DUBBO_CONFIG_BINDER_BEAN_NAME)
    38. @Scope(scopeName = SCOPE_PROTOTYPE)
    39. public ConfigurationBeanBinder relaxedDubboConfigBinder() {
    40. return new BinderDubboConfigBinder();
    41. }
    42. }

    3) @ConditionalOnProperty注解

            该注解的作用是解析application.yml/application.properties 里的配置生成条件来生效,也是与@Configuration注解一起使用。

    属性

    功能

    其他

    prefix

    读取配置里的前缀值为prefix的属性, 如果没有返回false

    name

    读取属性配置里的Key值,如果配置了prefix,那么需要先拼接prefix然后匹配havingValue值

    havingValue

    匹配属性里的值

    matchIfMissing

    当未找到对应的配置时是否匹配,默认为false, 如果为true,没有找到配置,那么也匹配。

            使用场景,例如在指定数据源时,指定datasource的type。例如包含如下配置使用Hikari数据源。

    spring.datasource.type=com.zaxxer.hikari.HikariDataSource

            在使用时,一般设置matchIfMissing=false, 这样条件没有匹配上的话会Spring在扫描bean时会自动跳过该配置类。 

            也可以设定matchIfMissing=true,这种场景例如缓存,我们可以这样配置默认是开启缓存的。

    1. @ConditionalOnProperty(name={cache.effect},marchIfMissing=true)
    2. public class CacheAutoConfiguration{
    3.    // ...
    4. }

            如果在application.properties里配置cache.effect=false, 那么该配置类就会跳过,这样配置就能使缓存不生效。 

  • 相关阅读:
    第六章集成测试
    目标检测——day45 基于水平边界框上滑动顶点的多朝向目标检测
    用户注册场景
    2024年阿里云4月服务器有哪些优惠活动?
    xargs命令
    JVM内存模型解析
    stm32——hal库学习笔记(ADC)
    jdk的bin目录下的工具
    HashMap 1.7 源码分析
    Mysql 索引与事务
  • 原文地址:https://blog.csdn.net/qq_33036061/article/details/126536173