Spring Boot @Condition 注解,组合条件你知道吗

上一篇文章 你应该知道的 @ConfigurationProperties 注解的使用姿式,这一篇就够了 介绍了如何经过 @ConfigurationProperties 注解灵活读取配置属性,这篇文章将介绍如何灵活配置 Spring Beanjava

写在前面

当咱们构建一个 Spring 应用的时候,有时咱们想在知足指定条件的时候才将某个 bean 加载到应用上下文中, 在Spring 4.0 时代,咱们能够经过 @Conditional 注解来实现这类操做
git

咱们看到 @Conditional 注解接收的参数是 extends Condition 接口的泛型类,也就是说,咱们要使用 @Conditional 注解,只须要实现 Condition 接口并重写其方法便可:
github

看到接口的 matches 方法返回的是 boolean 类型,是否是和咱们自定义 validation annotation 有些相似,都是用来判断是否知足指定条件。另外注意看,以上注解和接口都在 org.springframework.context.annotation package 中web

终于到了 Spring Boot 时代,在这个全新的时代,Spring Boot 在 @Conditional 注解的基础上进行了细化,无需出示复杂的介绍信 (实现 Condition 接口),只须要手持预约义好的 @ConditionalOnXxxx 注解印章的门票,若是验证经过,就会走进 Application Context 大厅面试

注解详解

Spring Boot 对 @Conditional 注解为咱们作了细化,这些注解都定义在 org.springframework.boot.autoconfigure.condition package 下
spring

逐个打开这 13 个注解,咱们发现这些注解上有相同的元注解:
app

从这些标记上咱们能够了解以下内容:框架

  • 均可以应用在 TYPE 上,也就是说,Spring 自动扫描的一切类 (@Configuration, @Component, @Service, @Repository, or @Controller) 均可以经过添加相应的 @ConditionalOnXxxx 来判断是否加载
  • 均可以应用在 METHOD 上,因此有 @Bean 标记的方法也能够应用这些注解
  • 都是用了 @Conditional 注解来标记,OnBeanCondition 等自定义 Condition 仍是实现了 Condition 接口的,换汤不换药,没什么神秘的,只不过作了更具象的封装罢了,来看类依赖图:

其实看这些注解字面意思已经能理解这些注解的含义,可是咱们仍是要说明具体的使用以及一些注意事项,我按照我的使用频次由高到低讲解:spring-boot

@ConditionalOnProperty

毫无疑问这个注解是榜首
工具

这个条件解释是: application.properties 或 application.yml 文件中 mybean.enable 为 true 才会加载 MyCondition 这个 Bean,若是没有匹配上也会加载,由于 matchIfMissing = true,默认值是 false。

@ConditionalOnBean 和 ConditionalOnMissingBean

有时候咱们须要某个 Bean 已经存在应用上下文时才会加载,那么咱们会用到 @ConditionalOnBean 注解:

与之相反,有时候咱们须要某个 Bean 不存在于应用上下文时才会加载,那么咱们会用到 @ConditionalOnMissingBean 注解

@ConditionalOnClass 和 @ConditionalOnMissingClass

不要嫌我废话,和上面的同样,只不过判断某个类是否存在于 classpath 中,这就不作过多说明了

@ConditionalOnExpression

若是咱们有更复杂的多个配置属性一块儿判断,那么咱们就能够用这个表达式了:

只有当两个属性都为 true 的时候才加载 MyModule,到这里要顺便揭晓上一篇文章 你应该知道的 @ConfigurationProperties 注解的使用姿式,这一篇就够了 灵魂追问 3,其中 :true 就是: 若是没有为该属性设置值,则为该属性设置默认值true, 其实这就是@Vaue 注解的规范,一切 SpEL 均可以应用在这里.

写到这,我经常使用的已经用完了,还要硬着头皮介绍其余几个内容 😄,开个玩笑,我们继续:

@ConditionalOnSingleCandidate

这个注解和 @ConditionalOnBean 相似,为了更好的说明该注解的使用 (实际上是 才疏学浅 ) ,我只能翻译一下类的注释了

只有指定类已存在于 BeanFactory 中,而且能够肯定单个候选项才会匹配成功

BeanFactory 存在多个 bean 实例,可是有一个 primary 候选项被指定(一般在类上使用 @Primary 注解),也会匹配成功。实质上,若是自动链接具备定义类型的 bean 匹配就会成功

目前,条件只是匹配已经被应用上下文处理的 bean 定义,自己来说,强烈建议仅仅在 auto-configuration 类中使用这个条件,若是候选 bean 被另一个 auto-configuration 建立,确保使用该条件的要在其后面运行

@ConditionalOnResource

若是咱们要加载的 bean 依赖指定资源是否存在于 classpath 中,那么咱们就可使用这个注解

看到这个 logback.xml 是否是很亲切,在咱们引入第三方工具类如 Dozer 等均可以添加相似的开关

接下来的是真冷门,你们有个印象,若是有须要,至少能想到用这些注解实现灵活配置就行了

@ConditionalOnJndi

只有指定的资源经过 JNDI 加载后才加载 bean

@ConditionalOnJava

只有运行指定版本的 Java 才会加载 Bean

@ConditionalOnWebApplication 和 @ConditionalOnNotWebApplication

只有运行在 web 应用里才会加载这个 bean

与之相反,在非 web 环境才加载 bean

@ConditionalOnCloudPlatform

这个注解冷的我呼吸都要中止了,只有运行在指定的云平台上才加载指定的 bean,CloudPlatform 是 org.springframework.boot.cloud 下一个 enum 类型的类,你们能够打开自行看看:

到此,Spring Boot 为咱们提供的这 13 个注解就介绍完了,可是没有结束,下面的一些冷门知识,你须要知道:

组合条件

组合条件 AND

若是咱们想多个条件一块儿应用,而且条件的关系是 and,咱们只须要在类上使用多个@ConditionalOnXxxx 就能够了 (你这也叫冷门?) ,固然也能够继承 AllNestedConditions类封装咱们多个条件

这样就有了组合 and 条件,只有内部全部条件都知足,才加载指定 bean

组合条件 OR

若是咱们但愿组合的条件是 or 的关系,咱们该怎么办呢? 咱们能够经过继承 AnyNestedCondition 来完成这一要求,示例代码和上面同样,你们自行打开 AnyNestedCondition 类,查看类说明便可

条件组合 NONE

有 and 和 or 就确定有 non(非),咱们能够经过继承 NoneNestedConditions 完成这一要求,你们自行查看便可

## 自定义注解
经过组合方式实现了多条件逻辑应用,咱们须要应用这些组合条件也就要自定义注解,其实文章开头已经讲过了,模仿内置的 13 个注解写就行了:

只须要经过@Conditional注解指定咱们自定义的 condition 类就行了,而后应用到你想用的地方就行了

仍是推荐你们看 RabbitMq 的 RabbitAutoConfiguration 类,这个类里面主流的注解都是用了 (只看这一个类就行了),你们看框架理解学习这些注解是更好的方式:

https://github.com/spring-pro...

总结

到这里,你已经了解了如何灵活配置 bean,结合以前的文章,相信的定义会更加灵活,但愿你们打开 IDE,自行查看这些注解,了解更多具体内容

灵魂追问

  1. SpringBoot 添加了 web starter,有哪些方法将其更改成非 web 应用?
  2. Java8 Stream 也有 findAny,findAll 这类的操做,这都是匹配,你有使用过吗?
  3. 看下面这段代码,若是 classpath 中没有 MyBean class,编译会报错,那这个注解什么用呢?
@Configuration    
@ConditionalOnClass(MyBean.class)
public class MyConfiguration{
    // omitted       
}

提升效率工具


推荐阅读


欢迎持续关注公众号:「日拱一兵」

  • 前沿 Java 技术干货分享
  • 高效工具汇总 | 回复「工具」
  • 面试问题分析与解答
  • 技术资料领取 | 回复「资料」
以读侦探小说思惟轻松趣味学习 Java 技术栈相关知识,本着将复杂问题简单化,抽象问题具体化和图形化原则逐步分解技术问题,技术持续更新,请持续关注......
相关文章
相关标签/搜索