第八节 条件装配案例讲解

一、条件装配的作用是什么

条件装配是 Spring 框架中一个强大的特性,使得开发者能够创建更加灵活和可维护的应用程序。在 Spring Boot 中,这个特性被大量用于自动配置,极大地简化了基于 Spring 的应用开发。

二、条件装配注解

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-autoconfigure</artifactId>
  <version>${version}</version>
</dependency>

下面以版本2.1.13.RELEASE为例子。 下面是包路径

org.springframework.boot.autoconfigure.condition.XXX

2.1 条件注解

2.2 条件注解说明

下面是相关注解的简单说明,标注颜色的可以重点关注

注解

作用

@ConditionalOnBean

当容器中存在指定的Bean时,满足条件。

@ConditionalOnMissingBean

当容器中不存在指定的Bean时,满足条件。

@ConditionalOnClass

当类路径上存在指定的类时,满足条件。

@ConditionalOnMissingClass

当类路径上缺少指定的类时,满足条件。

@ConditionalOnProperty

当存在指定的配置属性,并且属性值与给定的值相匹配时,满足条件。

@ConditionalOnResource

当指定的资源存在于类路径上时,满足条件。

@ConditionalOnExpression

基于SpEL表达式的结果,当表达式为true时,满足条件。

@ConditionalOnJava

当Java的版本匹配指定的条件时,满足条件。

@ConditionalOnWebApplication

当应用程序是一个Web应用时,满足条件。

@ConditionalOnNotWebApplication

当应用程序不是一个Web应用时,满足条件。

@ConditionalOnJndi

当指定的JNDI存在时,满足条件。

@ConditionalOnSingleCandidate

当容器中只存在一个指定的Bean,或者即使有多个也有一个被标记为首选时,满足条件。

前面5个可以重点关注,它是最常用的。在第三节中,我将分别针对上面的几个案例进行举例说明。

三、条件装配举例说明

用代码的方式来展示条件装配的作用,以及在实际生活中到底如何使用。

3.1 灵活性举例

场景描述:

假设我们正在开发一个多环境支持的应用程序,该应用在开发环境中使用基于内存的数据库(如 H2),而在生产环境中使用更稳定和持久的关系数据库(如 PostgreSQL)。

实现方式:

不使用条件装配时,我们可能需要在应用程序的不同版本中手动更改数据源配置,或者在代码中进行环境检查来决定使用哪个数据库。这样做会增加维护工作,也容易出错。

使用条件装配,我们可以利用 注解来根据环境自动配置不同的数据源:

@Configuration
@ConditionalOnProperty(name = "use-in-memory-db", havingValue = "true")
public class H2DatabaseConfig {
    // Configuration for H2 Database
}

@Configuration
@ConditionalOnProperty(name = "use-in-memory-db", havingValue = "false")
public class PostgresDatabaseConfig {
    // Configuration for PostgreSQL Database
}

例子解释:

在这个例子中,我们有两个配置类,分别为 H2DatabaseConfig 和 PostgresDatabaseConfig。它们都使用了 @ConditionalOnProperty 注解来判断一个名为 use-in-memory-db 的属性的值。

  • 如果 use-in-memory-db 属性设置为 true,Spring Boot 会实例化 H2DatabaseConfig 类并使用 H2 数据库配置。
  • 如果 use-in-memory-db 属性设置为 false,Spring Boot 会实例化 PostgresDatabaseConfig 类并使用 PostgreSQL 数据库配置

提示:案例演示了 @ConditionalOnProperty 使用方式。

3.2 自动装配案例

根据配置,选择使用不通的缓存实现类。

简化实现

public interface CacheService {
    void put(String key, Object value);
    Object get(String key);
}

Redis 缓存服务实现:

@Configuration
@ConditionalOnClass(name = "redis.clients.jedis.Jedis")
public class RedisCacheConfig {

    @Bean
    public CacheService redisCacheService() {
        return new RedisCacheService();
    }

    // RedisCacheService 实现了 CacheService 接口
    // 使用 Redis 客户端进行具体的缓存操作
}

内存缓存服务实现:

@Configuration
@ConditionalOnMissingClass(value = "redis.clients.jedis.Jedis")
public class InMemoryCacheConfig {

    @Bean
    public CacheService inMemoryCacheService() {
        return new InMemoryCacheService();
    }

    // InMemoryCacheService 实现了 CacheService 接口
    // 使用 Java Map 进行缓存操作
}

在这个例子中,我们有两个配置类 RedisCacheConfig 和 InMemoryCacheConfig,它们都定义了一个用于条件装配的 CacheService Bean。

@ConditionalOnClass(name = "redis.clients.jedis.Jedis") 注解在 RedisCacheConfig 类上,表明如果类路径包含 Redis 的 Jedis 客户端类,则创建和注册 RedisCacheService 为 CacheService 的实现。

相对地,@ConditionalOnMissingClass(value = "redis.clients.jedis.Jedis") 注解在 InMemoryCacheConfig 类上,表明如果类路径不包含 Redis 的 Jedis 客户端类,则创建和注册 InMemoryCacheService 为 CacheService 的实现。

在这个条件装配的例子中,Spring Boot 应用会自动检查 Redis 客户端库是否存在,并基于检查结果来决定使用哪个缓存实现。这个过程完全自动化,无需开发者介入,也无需修改配置文件。如果你将 Redis 客户端库添加到项目的依赖中,Spring Boot 将自动配置使用 RedisCacheService;如果移除了相关依赖,则会回退到使用 InMemoryCacheService。

提示:案例演示了 @ConditionalOnClassConditionalOnClass的使用方式。

3.4 避免条件冲突举例

假设我们的应用程序中既可以使用JPA来访问数据库,也可以使用MyBatis。但是,我们希望这两个持久层框架不要同时生效,以免它们尝试操作同一个数据库实体时产生冲突

JPA配置类:

@Configuration
@ConditionalOnClass(name = "org.springframework.data.jpa.repository.JpaRepository")
public class JpaConfig {
    // 这里配置JPA相关的Bean,例如EntityManagerFactory, TransactionManager等
}

MyBatis配置类:

@Configuration
@ConditionalOnClass(name = "org.mybatis.spring.SqlSessionFactoryBean")
@ConditionalOnMissingBean(type = "org.springframework.data.jpa.repository.JpaRepository")
public class MyBatisConfig {
    // 这里配置MyBatis相关的Bean,例如SqlSessionFactory, DataSource等
}

例子解释:

@ConditionalOnClass 注解检查类路径上是否存在指定的类。在这个例子中,JpaConfig 类上的 @ConditionalOnClass 注解会检查JPA的 JpaRepository 是否存在于类路径上,如果存在,那么JPA的相关配置就会被注册。

MyBatisConfig 类上同时使用了 @ConditionalOnClass 和 @ConditionalOnMissingBean 注解。@ConditionalOnClass 注解会检查类路径上是否存在MyBatis的 SqlSessionFactoryBean 类;而 @ConditionalOnMissingBean 注解则确保只有在不存在 JpaRepository 类型的Bean时,MyBatis的配置才会生效

避免Bean冲突:

这种配置方法确保了当两种持久层技术的类都存在于类路径上时,只有JPA的配置会生效,因为 JpaConfig 没有额外的限制条件。而MyBatis的配置则只有在JPA不可用(即类路径上没有 JpaRepository)时才会生效,从而避免了同时注册JPA和MyBatis持久层可能引起的Bean冲突。

举例说明,实际案例。以 tomcat 容器为例子。

请思考这样一个场景,为什么,我们的 SpringBoot 项目,不再关注 tomcat、jetty 容器了呢;他们的加载装配是如何实现的呢?

当Spring Boot在类路径上发现tomcat-embedded.jar时,它会自动配置Tomcat作为应用程序的默认服务器。同样,如果它发现jetty-embedded.jar,而没有发现Tomcat,那么它将配置Jetty服务器。

以下是简化后的Tomcat和Jetty自动配置的源码示例,用于解释Spring Boot是如何使用条件注解来实现自动配置的。

Tomcat自动配置:

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({Servlet.class, Tomcat.class, UpgradeProtocol.class})
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
public class TomcatServletWebServerFactoryConfiguration {

    @Bean
    public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
        return new TomcatServletWebServerFactory();
    }

}

上面的配置类使用了@ConditionalOnClass注解,它意味着只有当Servlet、Tomcat和UpgradeProtocol这三个类都存在于类路径上时,该配置类才会被考虑。此外,@ConditionalOnMissingBean注解确保只有在当前上下文中不存在ServletWebServerFactory类型的Bean时,才会创建TomcatServletWebServerFactory的Bean。

3.5 提升性能

避免加载和初始化不需要的组件,可以提升应用程序的启动速度和运行时性能

Spring Boot 条件装配通过确保只有在需要时才创建和注册特定的 Beans,从而帮助提高应用程序的启动速度和运行时性能。这将避免浪费资源去加载和初始化那些在当前应用程序环境中不需要的组件。

下面是一个代码示例,它展示了如何使用 Spring Boot 条件装配来决定是否配置一个用于性能监控的组件。

场景描述:

假设我们的应用程序包含一个性能监控组件,这个组件在生产环境中是有用的,但在开发和测试环境中可能不需要它,因为它可能会降低应用的性能和增加额外的资源消耗.

@Configuration
@ConditionalOnProperty(name = "app.monitoring.enable", havingValue = "true")
public class PerformanceMonitoringConfig {

    @Bean
    public PerformanceMonitor performanceMonitor() {
        // 初始化性能监控组件
        return new PerformanceMonitor();
    }

    // 其它与性能监控相关的Beans...
}

在这个例子中,我们创建了一个配置类 PerformanceMonitoringConfig,它包含了创建 PerformanceMonitor Bean 的方法。类上的 @ConditionalOnProperty 注解告诉 Spring Boot,只有当 app.monitoring.enable 属性的值设置为 true 时,才创建 PerformanceMonitor Bean。

应用配置文件:

开发或测试环境 application-dev.properties 或 application-test.properties:

# 在开发和测试环境中,禁用性能监控
app.monitoring.enable=false

生产环境 :

# 在生产环境中,启用性能监控
app.monitoring.enable=true

提升性能的效果:

通过上述条件装配的方式,Spring Boot应用会根据配置文件中的属性值决定是否加载和初始化性能监控组件。这种机制确保了在开发和测试环境中,不会因为性能监控组件的存在而造成不必要的性能开销;而在生产环境中,性能监控组件才会被激活,为我们提供关键的性能数据。

这样的条件装配策略有助于在不同的环境中优化资源使用和应用性能,因为只有真正需要的组件才会被加载,从而加快了应用程序的启动时间,并在运行时提高了性能。

3.6 Profile(补充)

根据环境不同(开发环境和生产环境)来使用不同的邮件服务实现。在生产环境中,我们使用真实的邮件服务,而在开发环境中,我们使用一个模拟的邮件服务以避免发送真实的邮件。

public interface EmailService {
    void sendEmail(String to, String subject, String content);
}
  1. 定义邮件服务接口:

除去上面的注解外,在 Spring 中也提供了 Profile 来实现一定的条件装配。

生产环境的邮件服务实现:

@Profile("prod")
@Service
public class SmtpEmailService implements EmailService {
    // SMTP邮件服务相关的配置和方法
    public void sendEmail(String to, String subject, String content) {
        // 实际的邮件发送逻辑
    }
}

开发环境的邮件服务模拟实现:

@Profile("dev")
@Service
public class MockEmailService implements EmailService {
    // 模拟邮件服务的相关配置和方法
    public void sendEmail(String to, String subject, String content) {
        System.out.println("Mock email sent to " + to + " with subject " + subject);
        // 其他模拟操作
    }
}

在这个例子中,我们定义了一个邮件服务的接口 EmailService 和两个实现 SmtpEmailService 以及 MockEmailService。每个实现类上都使用了 Spring 的 @Profile 注解来指定它应该在哪个应用配置文件激活的情况下被注册。

  • @Profile("prod") 表示 SmtpEmailService 将仅在应用程序的 prod 配置文件激活时注册到 Spring 容器中。
  • @Profile("dev") 表示 MockEmailService 将仅在应用程序的 dev 配置文件激活时注册到 Spring 容器中。

在不同的环境中,通过设置 spring.profiles.active 属性,我们可以决定激活哪个配置文件。

3.7 更多场景

还可以实现模块化的加载,不仅仅是停留在单独的一个类上面。

Spring Boot的条件装配可以支持模块化开发,模块化是指将一个应用程序分解成一组可以独立开发、测试和部署的模块。条件装配允许开发者根据应用程序的不同部分是否存在或者某个条件是否满足来实现模块的动态加载与集成。

特别适合多云场景; 比如当前,有很多信创项目,完全可以使用条件装配来加载不通的实现类。

作者曾经,使用条件装配改造过登录模块。

  1. 使用扫描登录
  2. 使用密码登录
  3. 使用 OAUTH 登录

......

除去上面案例,还可以进行改造。比如 mq 的改造。不同环境使用不同的 mq 进行改造等。

  1. 信创环境使用 activimq
  2. 云上使用 rocketmq

3.....

还有数据库的适配,mysql、pg等。

四、本章小结

系统通过上面的几个案例,让你感受到了条件装配它的作用和好处。 方便以后在工作项目中如何合适地使用它们。

已同步发布到公众号:面汤放盐 第八节 条件装配案例讲解 (qq.com)

掘金账号:​​​​​​​第八节 条件装配案例讲解 - 掘金 (juejin.cn)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/641013.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

为什么要用虚拟时钟Virtual clock?

通常RTL设计要求对芯片/module的输入信号进行reg_in打拍处理&#xff0c;对芯片/module的输出也要求做reg_out打拍处理&#xff0c;这是良好的代码习惯&#xff0c;为时序收敛留下足够裕量&#xff0c;也避免顶层例化综合后的子模块时出现模块间IO时序不满足的情况。综合阶段可…

DNF手游攻略:角色培养与技能搭配!游戏辅助!

角色培养和技能搭配是《地下城与勇士》中提升战斗力的关键环节。每个职业都有独特的技能和发展路线&#xff0c;合理的属性加点和技能搭配可以最大化角色的潜力&#xff0c;帮助玩家在各种战斗中立于不败之地。接下来&#xff0c;我们将探讨如何有效地培养角色并搭配技能。 角色…

亿图图示——文本换行

一、点击文本框&#xff0c;选择更多 二、勾选文本换行

数据结构和算法基础(二)

树和二叉树——树的基本概念 树和二叉树——树转二叉树 树和二叉树——查找二叉树&#xff08;二叉排序树&#xff09; 树和二叉树——构造霍夫曼树&#xff08;最优&#xff09; 树和二叉树——线索二叉树 树和二叉树——平衡二叉树 图——基本概念 1、有向图 2、无向图 3、完…

Platformer Project

Platformer项目适合那些寻找坚实基础来构建你梦想中的3D平台游戏的人,提供受该类型最具影响力游戏启发的核心机制。 一般功能 移动支持; 自定义运动学角色控制器; Humanoid Rig支持(共享动画); 保存/加载(二进制、JSON或Playerprefs); 支持多个存储槽; 三星、硬币和最…

Dockerfile使用

1.Dockerfile是什么 官网地址 https://docs.docker.com/reference/dockerfile/概念 是什么 Dockerfile 是用于构建 Docker 镜像的文本文件&#xff0c;它包含一系列的指令&#xff08;instructions&#xff09;和参数&#xff0c;用于描述如何构建和配置镜像。 Dockerfile 是…

微信小程序中van-tab的title(动态)根据文本内容,自适应宽度

小程序van-tab的title&#xff08;动态&#xff09;根据文本内容&#xff0c;自适应宽度 效果图代码主要调整点 效果图 代码 <van-tabs color"#00aaff" active"{{ active }}" bind:click"onTabChange"><van-tab title"7天内&quo…

游戏后台开发技术全面解析

在这个数字时代&#xff0c;游戏产业已经成为全球最受欢迎的娱乐方式之一。从简单的手机游戏到复杂的大型多人在线角色扮演游戏&#xff08;MMORPG&#xff09;&#xff0c;游戏的世界正变得越来越丰富和多样化。而这一切的背后&#xff0c;都离不开强大的游戏后台技术支持。在…

【网络技术】【Kali Linux】Wireshark嗅探(十四)QUIC(快速UDP互联网连接)协议报文捕获及分析

往期 Kali Linux 上的 Wireshark 嗅探实验见博客&#xff1a; 【网络技术】【Kali Linux】Wireshark嗅探&#xff08;一&#xff09;ping 和 ICMP 【网络技术】【Kali Linux】Wireshark嗅探&#xff08;二&#xff09;TCP 协议 【网络技术】【Kali Linux】Wireshark嗅探&…

Mac电脑太卡了怎么办 Mac电脑常见问题 cleanmymacX有必要买吗

当我们遇到mac电脑出现卡顿的情况&#xff0c;首先应排除是否是电脑硬件的问题&#xff0c;可以通过重启电脑来检测是否硬盘或程序是否发生错误。其次对电脑进行全面的健康检测&#xff0c;找到具体卡顿问题。 磁盘空间不足是导致电脑运行缓慢的常见原因之一。定期清理不需要的…

PMBOK® 第六版 项目经理的角色

项目经理普遍是一个责任大但权力有限的角色&#xff0c;是一个综合的中层领导者&#xff0c;负责项目从启动到收尾的全过程。他需要整合项目管理的各个方面&#xff0c;以确保项目目标的实现&#xff0c;并满足相关方的期望和需求。在工作中&#xff0c;项目经理大部分时间都用…

【面试干货】杨辉三角形

【面试干货】杨辉三角形 1、实现思想2、代码实现 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 杨辉三角形&#xff08;也称帕斯卡三角形&#xff09;是一个规则的数字三角形&#xff0c;它的构造方法是&#xff0c;第一行只有一个数字1&a…

SQL Server基础学习笔记

SQL Server基础学习笔记 SQL Server简介 SQL Server是微软开发的一种关系数据库管理系统&#xff08;RDBMS&#xff09;。它是一个功能强大且广泛使用的数据库平台&#xff0c;支持存储、管理和检索数据&#xff0c;并提供各种工具和功能来提高开发和管理效率。 安装与配置 …

麻省理工出品!这个自动化神器让你的电脑自己工作

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

建议收藏 | 2023年生物学类SCI期刊影响因子最新预测,Molecular Plant遥遥领先

公众号&#xff1a;生信漫谈&#xff0c;获取最新科研信息&#xff01; 建议收藏 | 2023年生物学类SCI期刊影响因子最新预测&#xff0c;Molecular Plant遥遥领先https://mp.weixin.qq.com/s/tFINUzZ1l4H9x1HWTq1kFg 2023年生物学类SCI期刊影响因子最新预测&#xff0c;Molecu…

大佬大讲堂(1)电机及其驱动内核-自适应观察器

点击上方 “机械电气电机杂谈 ” → 点击右上角“...” → 点选“设为星标 ★”&#xff0c;为加上机械电气电机杂谈星标&#xff0c;以后找夏老师就方便啦&#xff01;你的星标就是我更新动力&#xff0c;星标越多&#xff0c;更新越快&#xff0c;干货越多&#xff01; 关注…

React 中的jsx 的语法使用

react 中是使用 JSX 编写标签的 它是可选的&#xff0c;但大多数 React 项目会使用 JSX&#xff0c;主要是它很方便。所有 我们推荐的本地开发工具 都开箱即用地支持 JSX。 JSX 比 HTML 更加严格。你必须闭合标签&#xff0c;如 <br />。你的组件也不能返回多个 JSX 标…

冷干机使用中的注意事项

冷干机使用中的注意事项 使用冷干机时&#xff0c;以下是几个注意事项&#xff1a; 安装位置&#xff1a;选择一个通风良好、温度适宜的位置安装冷干机。确保周围环境没有过多的灰尘、腐蚀性气体或其他污染物&#xff0c;以免对冷干机的正常运行和寿命产生不利影响。 电源要求…

高效使用 LaTeX 技巧

但对于一般人而言&#xff0c;你不需要通过学习 Vim 来达到高效编辑 LaTeX 的方式。而是通过一些比较容易实现的方式&#xff0c;使得你能够在原来的基础上更加高效得使用 LaTeX&#xff0c;并达到以思考的速度输入 LaTeX 的方式。 在第一部分&#xff0c;我会首先介绍高效编辑…

IPKISS ------ AMF 添加自定义层

IPKISS ------ AMF 添加自定义层 正文 正文 很多时候&#xff0c;我们想要添加属于我们自己的层&#xff0c;此时我们需要向 AMF pdk 中的 gdsii.py 和 layers.py 文件添加层的信息。这两个文件的目录如下&#xff1a; 在 gdsii.py 文件下的 TECH.GDSII.LAYERTABLE 字典中我们…