天天看点

「SpringBoot」条件注解@Conditional

作者:嘟null

简概

https://docs.spring.io/spring-boot/docs/2.7.5/reference/htmlsingle/#features.developing-auto-configuration.condition-annotations

您几乎总是希望在自动配置类中包含一个或多个@Conditional注解。@ConditionalOnMissingBean注解是一个常见的例子,用于允许开发人员在不满意您的默认值时覆盖自动配置。

Spring Boot包含许多@Conditional注解,您可以在自己的代码(注解@Configuration的类或单独的@Bean方法)上重用这些注解。这些注解包括:

  • Class Conditions
  • Bean Conditions
  • Property Conditions
  • Resource Conditions
  • Web Application Conditions
  • SpEL Expression Conditions

Class Conditions

@ConditionalOnClass和@ConditionalOnMissingClass注解允许根据特定类的存在或不存在来决定是否包含@Configuration类。由于注解元数据是通过使用ASM解析的,所以可以使用value属性来引用真正的类,即使这个类实际上可能不会出现在正在运行的应用程序类路径上。如果您希望通过使用String值指定类名,也可以使用name属性。

这种机制并不以同样的方式应用于@Bean方法,在@Bean方法中,通常返回类型是条件的目标:在方法上的条件应用之前,JVM将加载类和潜在处理的方法引用,如果类不存在,这些方法引用将失败。【一个可参考点:https://cloud.tencent.com/developer/article/1449288】

要处理这种情况,可以使用一个单独的@Configuration类来隔离条件,如下面的示例所示:

import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@AutoConfiguration
// Some conditions ...
public class MyAutoConfiguration {

    // Auto-configured beans ...

    @Configuration(proxyBeanMethods = false)
    @ConditionalOnClass(SomeService.class)
    public static class SomeServiceConfiguration {

        @Bean
        @ConditionalOnMissingBean
        public SomeService someService() {
            return new SomeService();
        }

    }
}           

如果使用@ConditionalOnClass或@ConditionalOnMissingClass作为元注解的一部分来组成自己的合成注解,在这种情况没有被处理时,必须使用name来引用类。

Bean Conditions

@ConditionalOnBean和@ConditionalOnMissingBean注解允许根据特定bean的存在或不存在来决定是否包含bean。您可以使用value属性按type或name指定bean。search属性允许您限制在搜索bean时应该考虑的ApplicationContext层次结构。

当放在@Bean方法上时,目标类型默认为方法的返回类型,如下例所示:

import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;

@AutoConfiguration
public class MyAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public SomeService someService() {
        return new SomeService();
    }

}           

在上面的示例中,如果ApplicationContext中没有包含someService类型的bean,则将创建someService bean。

需要特别注意添加bean定义的顺序,因为这些条件是根据到目前为止所处理的内容来计算的。由于这个原因,我们建议只在自动配置类上使用@ConditionalOnBean和@ConditionalOnMissingBean注解(因为这能保证在添加任何用户定义的bean definitions后再加载这些注解)。

@ConditionalOnBean和@ConditionalOnMissingBean不阻止@Configuration类的创建。在类级别使用这些条件与用注解标记其中包含的@Bean方法之间的唯一区别是,如果条件不匹配,前者会阻止将@Configuration类注册为bean

在声明@Bean方法时,在方法的返回类型中提供尽可能多的类型信息。例如,如果bean的具体类实现了一个接口,那么bean方法的返回类型应该是具体类而不是接口。在使用bean conditions时,在@Bean方法中提供尽可能多的类型信息尤其重要,因为它们的计算只能依赖于方法签名中可用的类型信息。

Property Conditions

@ConditionalOnProperty注解允许基于Spring Environment property来决定是否配置。使用前缀和名称属性指定应该检查的属性。缺省情况下,匹配任何存在且不等于false的属性。还可以通过使用havingValue和matchIfMissing属性创建更高级的检查。

Web Application Conditions

@ConditionalOnWebApplication和@ConditionalOnNotWebApplication注解允许根据应用程序是否是一个“web application”来决定是否配置。基于servlet的web应用程序是任何使用Spring WebApplicationContext、定义了session scope或具有ConfigurableWebEnvironment的应用程序。响应式web应用程序是任何使用ReactiveWebApplicationContext或ConfigurableReactiveWebEnvironment的应用程序。

@ConditionalOnWarDeployment注解允许根据应用程序是否是部署到容器的传统WAR应用程序来决定是否包含配置。此条件不适用于使用嵌入式服务器运行的应用程序。

SpEL Expression Conditions

@ConditionalOnExpression注解允许根据SpEL expression的结果决定是否包含配置。

在表达式中引用bean将导致在上下文刷新处理中很早就初始化该bean。因此,bean将不能进行后处理(例如配置属性绑定),并且它的状态可能是不完整的