Spring Boot2.x条件注解@Conditional详解及实战

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: Spring Boot2.x条件注解@Conditional详解及实战

image.png@Conditional是Spring Boot中大量使用的注解之一,它可以根据是否满足某一个特定条件来决定是否加载指定的Bean。本文带领大家详细了解该注解的基本功能及实战使用。

条件注解@Conditional

@Conditional是SpringFramework提供的注解,位于 org.springframework.context.annotation包内,被其注解的类会根据指定的条件进行判断,如果满足条件则进行Bean的实例化及加载,如果不符合条件则不进行加载。

比如在Spring Boot的自动配置中经常用在这样的场景:当某个待自动配置组件的jar包在类路径下时,自动配置该组件的一个或多个Bean。

除了直接使用@Conditional注解来进行判断,在Spring Boot中通常情况下使用的更多的是由@Conditional组合的具体特殊场景的注解。比如,@ConditionalOnClass注解用来检查类路径下是否有指定的类。其相关使用源码如下:

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnClassCondition.class)
public @interface ConditionalOnClass {
// ...
}

@Conditional使用形式:

  • 类型级别,可以在@Component或是@Configuration类上使用;
  • 原型级别,用于特定自动场景注解上的注解(如上:ConditionalOnClass);
  • 方法级别,作用在任何@Bean方法上(如下例)。

另外,condition注解是不会继承的,如果一个父类使用了conditional注解,其子类是不会拥有conditions的。

源码解析

为了更好的理解@Conditional注解的使用,我们先看一下它的源代码定义:

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
    // 该属性传入实现Conditions的类
    Class<? extends Condition>[] value();
}

通过源码可以看出,Conditional的属性为实现了Condition接口的类的数组。在使用的过程中只有满足了Condition接口实现类定义的条件才会进行实例化操作。

顺便再看一下Condition接口的定义:





@FunctionalInterfacepublic interface Condition {  boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);}

其中只定义了一个返回类型为boolean的方法,也就是说返回值为true则被注解类进行实例化,返回值为false则不进行实例化。

实例讲解

下面我们先通过一个实例来演示一下@Conditional注解的具体使用。了解了@Conditional的基本功能和使用场景,要实现具体的例子,大概可分为两步:第一,实现Condition接口定义实例化场景;第二,在具体的业务场景中使用@Conditional注解并指定其属性为上面的实现类。

首先定义一个简单的模型来实现:配置文件中可以指定数据库的类型,当指定不同的类型时,实例化不同的Bean。

配置文件中配置属性如下:

db.type=mysql

针对该配置文件定义Mysql和Oracle的Condition条件判断实现。

Mysql的Condition实现:








public class MysqlCondition implements Condition {  @Override  public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {    String dbType = context.getEnvironment().getProperty("db.type");    return "mysql".equalsIgnoreCase(dbType);  }}

Oralce的Condition实现:








public class OracleCondition implements Condition {  @Override  public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {    String dbType = context.getEnvironment().getProperty("db.type");    return "oracle".equalsIgnoreCase(dbType);  }}

两个Condition实现很简单,从环境变量中获得指定配置属性值,如果匹配对应的字符串,则表示符合条件并返回。

下面针对上面的定义进行使用,为了方便调用我们让对应的Mysql和Oracle配置实现均实现同一个接口ConfigBean。




public interface DbConfigBean {  void printInfo();}

具体实现如下:







public class MysqlDbConfigBean implements DbConfigBean {  @Override  public void printInfo(){    System.out.println("I am Mysql!");  }}







public class OracleDbConfigBean implements DbConfigBean {
  @Override  public void printInfo(){    System.out.println("I am Oracle!");  }}

也就是说这两个实现类,都有打印对应Bean的信息的方法。

此时通过@Conditional来对这两个Bean的实例化进行注解判断。
















@Configurationpublic class DbConfig {
  @Bean  @Conditional(MysqlCondition.class)  public DbConfigBean mysql() {    return new MysqlDbConfigBean();  }
  @Bean  @Conditional(OracleCondition.class)  public DbConfigBean oracle() {    return new OracleDbConfigBean();  }}

在配置类DbConfig中,定义了实例化DbConfigBean的两个方法,每个方法都通过@Conditional指定实例化的条件,当满足条件时就会创建对应的Bean。

注意此处两个Bean的实例化是互斥的,如果在实践过程中两个Bean有可能同时存在则使用@Primary注解来定义同时存在时使用哪个。

至此,@Conditional的定义和使用便完成了,下面看对具体Bean的使用和单元测试。

具体使用示例:











@Servicepublic class DbService {
  @Autowired  private DbConfigBean configBean;    public void getDbInfo(){    configBean.printInfo();  }}

单元测试示例:












@SpringBootTestclass DbServiceTest {
  @Resource  private DbService dbService;    @Test  void getDbInfo() {    dbService.getDbInfo();  }}

此时根据配置文件中配置的是mysql还是oracle会调用对应的方法进行打印。

我们这里是针对指定的Bean使用@Conditional,如果一个@Configuration类被标注为@Conditional,则该类的所有的@Bean方法, @Import注解和@ComponentScan注解,都依从于该条件。

@Conditional衍生注解

@Conditional由Spring提供,而在Spring Boot中衍生出了以下相关的注解:

  • @ConditionalOnBean:当容器中有指定Bean的条件下。
  • @ConditionalOnClass:当classpath类路径下有指定类的条件下。
  • @ConditionalOnCloudPlatform:当指定的云平台处于active状态时。
  • @ConditionalOnExpression:基于SpEL表达式的条件判断。
  • @ConditionalOnJava:基于JVM版本作为判断条件。
  • @ConditionalOnJndi:在JNDI存在的条件下查找指定的位置。
  • @ConditionalOnMissingBean:当容器里没有指定Bean的条件。
  • @ConditionalOnMissingClass:当类路径下没有指定类的条件下。
  • @ConditionalOnNotWebApplication:当项目不是一个Web项目的条件下。
  • @ConditionalOnProperty:当指定的属性有指定的值的条件下。
  • @ConditionalOnResource:类路径是否有指定的值。
  • @ConditionalOnSingleCandidate:当指定的Bean在容器中只有一个,或者有多个但是指定了首选的Bean。
  • @ConditionalOnWebApplication:当项目是一个Web项目的条件下。

以上组合注解均位于spring-boot-autoconfigure jar包下的org.springframework.boot.autoconfigure.condition包下。


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
27天前
|
XML Java 数据格式
SpringBoot入门(8) - 开发中还有哪些常用注解
SpringBoot入门(8) - 开发中还有哪些常用注解
48 0
|
1月前
|
XML JSON Java
SpringBoot必须掌握的常用注解!
SpringBoot必须掌握的常用注解!
57 4
SpringBoot必须掌握的常用注解!
|
12天前
|
前端开发 Java Spring
探索Spring MVC:@Controller注解的全面解析
在Spring MVC框架中,`@Controller`注解是构建Web应用程序的基石之一。它不仅简化了控制器的定义,还提供了一种优雅的方式来处理HTTP请求。本文将全面解析`@Controller`注解,包括其定义、用法、以及在Spring MVC中的作用。
28 2
|
1月前
|
JSON Java 数据库
SpringBoot项目使用AOP及自定义注解保存操作日志
SpringBoot项目使用AOP及自定义注解保存操作日志
43 1
|
1月前
|
存储 安全 Java
springboot当中ConfigurationProperties注解作用跟数据库存入有啥区别
`@ConfigurationProperties`注解和数据库存储配置信息各有优劣,适用于不同的应用场景。`@ConfigurationProperties`提供了类型安全和模块化的配置管理方式,适合静态和简单配置。而数据库存储配置信息提供了动态更新和集中管理的能力,适合需要频繁变化和集中管理的配置需求。在实际项目中,可以根据具体需求选择合适的配置管理方式,或者结合使用这两种方式,实现灵活高效的配置管理。
17 0
|
Java Spring 数据格式
|
3月前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。
|
2月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
193 2
|
28天前
|
缓存 IDE Java
SpringBoot入门(7)- 配置热部署devtools工具
SpringBoot入门(7)- 配置热部署devtools工具
39 2
 SpringBoot入门(7)- 配置热部署devtools工具
|
24天前
|
存储 运维 安全
Spring运维之boot项目多环境(yaml 多文件 proerties)及分组管理与开发控制
通过以上措施,可以保证Spring Boot项目的配置管理在专业水准上,并且易于维护和管理,符合搜索引擎收录标准。
38 2