引言

在软件开发中,进行本地单元测试是一项常规且必要的任务。然而,在进行单元测试时,有时需要启动一些中间件服务,如Kafka、Elasticjob等。举例来说,我曾经遇到过一个问题:项目中使用了Redisson锁,但由于Redisson版本较低,在Mac环境下偶尔会报错# RedisConnectionException: Unable to init enough connections amount。鉴于升级版本带来的风险,以及问题仅在本地启动时出现,我决定在本地环境中排除Redisson的Starter,从而避免影响其他环境的配置。那么,我们应该如何做呢?

我们以上篇介绍如何自定义Starter中的文章中示例CoderAcademyStarter为例。我们引入了这个starter。

Starter自动配置类的排除

在《SpringBoot如何自定义Starter》中,我们介绍了如何在META-INF/spring.factories文件中使用org.springframework.boot.autoconfigure.EnableAutoConfiguration来指定Starter的自动配置类。Spring Boot启动时会扫描所有已引入jar包中的spring.factories文件,并根据EnableAutoConfiguration键下的类来加载和执行相应的自动配置逻辑。当我们不希望应用启动时使用该Starter的功能时,就需要排除自动配置类。

我们可以通过spring.autoconfigure.exclude属性排除CoderAcademyStarter的自动配置类:

spring.autoconfigure.exclude=com.springboot.starter.coderacademy.config.CoderAcademyAutoConfig

spring.autoconfigure.exclude是Spring Boot中的一个属性,用于指定在自动配置过程中要排除的自动配置类。通过设置该属性,我们可以明确告知Spring Boot不要自动配置指定的类,即使它们满足自动配置的条件。当需要禁用特定的自动配置类时,可以在application.propertiesapplication.yml中设置spring.autoconfigure.exclude属性,并提供要排除的自动配置类的完全限定类名。这样,Spring Boot在自动配置过程中将不会考虑这些类。

此时,如果我们在使用CoderAcademyService时会出现错误:

根据不同环境排除Starter自动配置类

在日常开发中,我们通常需要针对不同的环境指定不同的配置。我们可以通过spring.actice.profiles属性来指定不同环境的配置文件的加载。例如,我们可以在本地指定spring.actice.profiles=local,然后创建一个application-local.properties的配置文件,在其中指定spring.autoconfigure.exclude

另外,我们还可以实现ApplicationListener<ApplicationContextInitializedEvent>接口,通过监听上下文初始化事件来根据环境变量的标识排除Starter的自动配置类。当Spring应用程序的ApplicationContext被初始化时,将触发ApplicationContextInitializedEvent事件。通常,在应用程序的上下文初始化过程中会先加载bean定义、执行后处理器等操作。因此,通过监听ApplicationContextInitializedEvent事件,我们可以在Spring容器初始化的早期阶段执行一些定制化的逻辑。

我们可以通过实现ApplicationListener<ApplicationContextInitializedEvent>接口,根据一些环境变量的标识排除Starter的自动配置类。例如,我们可以定义一个coderacademy.enable的标识来决定是否扫描Starter。以下是一个示例:

import org.springframework.boot.context.event.ApplicationContextInitializedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.ConfigurableEnvironment; @Configuration
public class EnvironmentHandler implements ApplicationListener<ApplicationContextInitializedEvent> { @Override
public void onApplicationEvent(ApplicationContextInitializedEvent event) {
ConfigurableEnvironment environment = event.getApplicationContext().getEnvironment();
if (environment.getProperty("coderacademy.enable") != null && "false".equals(environment.getProperty("coderacademy.enable"))) {
System.setProperty("spring.autoconfigure.exclude", "com.springboot.starter.coderacademy.config.CoderAcademyAutoConfig");
}
}
}

然后,在启动应用时,通过-Dcoderacademy.enable=false指定排除Starter的自动配置类。这种方式特别适用于本地启动应用时排除Starter或其他Bean的初始化。

当然本地启动也可以直接通过-Dspring.autoconfigure.exclude=com.springboot.starter.coderacademy.config.CoderAcademyAutoConfig也可以满足排除Starter的配置。

自定义Starter Bean排除

在《SpringBoot如何自定义Starter》文中,我们还提到了一种调用方使用Starter的方式,我们可以不是用自动配置类的Starter,可以自定义配置的信息,在手动创建Starter对应的服务的Bean。例如:

@Data
@Configuration
public class StarterConfig { @Value("${springboot.coderacademy.name}")
private String staterMsg; @Bean
public CoderAcademyService coderAcademyService(){
CoderAcademyConfig coderAcademyConfig = new CoderAcademyConfig();
coderAcademyConfig.setUrl(staterMsg);
return new CoderAcademyService(coderAcademyConfig);
}
}

对于这种情况,我们可以使用Spring Boot的注解@ConditionalOnProperty来控制是否创建Bean。@ConditionalOnProperty是一个条件注解,根据配置属性的值来决定是否应该创建一个Bean或应用某个配置。具体来说,@ConditionalOnPropertyname属性表示配置属性的名称,havingValue属性表示配置属性的期望值,默认为truematchIfMissing属性表示当配置属性不存在时是否匹配条件,默认为false

因此,我们可以给CoderAcademyService的Bean添加@ConditionalOnProperty注解:

@Data
@Configuration
public class StarterConfig { @Value("${springboot.coderacademy.name}")
private String staterMsg; @ConditionalOnProperty(name = "coderacademy.enable", havingValue = "true", matchIfMissing = true)
@Bean
public CoderAcademyService coderAcademyService(){
CoderAcademyConfig coderAcademyConfig = new CoderAcademyConfig();
coderAcademyConfig.setUrl(staterMsg);
return new CoderAcademyService(coderAcademyConfig);
}
}

这样,我们在启动应用时可以通过-Dcoderacademy.enable=false变量来控制是否创建CoderAcademyService,而设置了matchIfMissing=true,即使其他环境没有该环境变量也不受影响。

除了@ConditionalOnProperty之外,Spring Boot还提供了其他一些条件注解,用于根据不同的条件来决定是否应该创建Bean或者是否应该应用某个配置。一些常见的条件注解包括:

  1. @ConditionalOnClass:当类路径中存在指定的类时,才会创建Bean或应用配置。
  2. @ConditionalOnMissingClass:当类路径中不存在指定的类时,才会创建Bean或应用配置。
  3. @ConditionalOnBean:当容器中存在指定的Bean时,才会创建Bean或应用配置。
  4. @ConditionalOnMissingBean:当容器中不存在指定的Bean时,才会创建Bean或应用配置。
  5. @ConditionalOnExpression:当满足SpEL表达式定义的条件时,才会创建Bean或应用配置。
  6. @ConditionalOnJava:当JVM运行的Java版本符合指定条件时,才会创建Bean或应用配置。
  7. @ConditionalOnWebApplication:当运行的环境是Web应用程序时,才会创建Bean或应用配置。
  8. @ConditionalOnNotWebApplication:当运行的环境不是Web应用程序时,才会创建Bean或应用配置。

总结

本文介绍了在Spring Boot项目中如何排除Starter自动配置类,以及根据不同环境动态排除配置的方法。通过spring.autoconfigure.exclude属性和条件注解如@ConditionalOnProperty,我们可以灵活控制Bean的创建和配置的应用,从而更好地适应不同的部署环境和需求。

本文已收录于我的个人博客:码农Academy的博客,专注分享Java技术干货,包括Java基础、Spring Boot、Spring Cloud、Mysql、Redis、Elasticsearch、中间件、架构设计、面试题、程序员攻略等

玩转SpringBoot:动态排除Starter配置,轻松部署的更多相关文章

  1. 【玩转SpringBoot】给自动配置来个整体大揭秘

    上一篇文章中提到的条件注解,只是自动配置整体解决方案中的一个环节而已,可以说是管中窥豹. 本文就逐步擦除迷雾,让整体浮现出来,这样就会有一个宏观的认识. 除了写代码之外,还能干点什么? 提到“配置”这 ...

  2. 【玩转SpringBoot】异步任务执行与其线程池配置

    同步代码写起来简单,但就是怕遇到耗时操作,会影响效率和吞吐量. 此时异步代码才是王者,但涉及多线程和线程池,以及异步结果的获取,写起来颇为麻烦. 不过在遇到SpringBoot异步任务时,这个问题就不 ...

  3. 【玩转SpringBoot】看似复杂的Environment其实很简单

    喜欢写代码,讨厌配环境 我相信这十个字的小标题代表了大多数码农的心声. 十年前读大学时,学校开设了C语言还有C++.但是学习这两种语言,对于新手来说非常没有成就感. 于是我就在校门口买个光盘,装个VS ...

  4. 【玩转SpringBoot】翻身做主人,一统web服务器

    寄人篱下的日子 一直以来受传统影响,我们的web工程总是打成war包,然后放入tomcat的webapps目录下面. 如下图01: 当tomcat启动时,会去解压war包,然后运行web工程.这大家都 ...

  5. 【玩转SpringBoot】让错误处理重新由web服务器接管

    其实web服务器是会处理错误的 在web.xml还是随处可见的年代时(确实有点老黄历了),下面的这些配置应该都不陌生. 根据错误代码处理错误,如下图01: 根据异常类型处理错误,如下图02: 不过我们 ...

  6. 【玩转SpringBoot】通过事件机制参与SpringBoot应用的启动过程

    生命周期和事件监听 一个应用的启动过程和关闭过程是归属到“生命周期”这个概念的范畴. 典型的设计是在启动和关闭过程中会触发一系列的“事件”,我们只要监听这些事件,就能参与到这个过程中来. 要想监听事件 ...

  7. 【玩转SpringBoot】SpringBoot应用的启动过程一览表

    SpringBoot应用的启动方式很简单,就一行代码,如下图01: 其实这行代码背后主要执行两个方法,一个是构造方法,一个是run方法. 构造方法主要内容就是收集一些数据,和确认一些信息.如下图02: ...

  8. 【玩转SpringBoot】用好条件相关注解,开启自动配置之门

    自动配置隐含两层含义,要搞清楚 上帝让程序员的发量减少,是为了让他变得更聪明,如果有一天聪明到了极点,那就是绝顶聪明. 据说在大脑高速运转下,这样更有利于散热,不至于核心温度过高而产生告警. 聪明的大 ...

  9. SpringBoot 动态配置邮箱发件人

    SpringBoot 动态配置邮箱发件人 现在的消息模块少不了邮件发送.短信发送和手机推送的功能.邮件发送的功能历史最为悠久,也算的上烂大街的功能.一般在配置文件中设置好邮箱地址.账号.密码和发件服务 ...

  10. SpringBoot集成Mybatis(0配置注解版)

    Mybatis初期使用比较麻烦,需要各种配置文件.实体类.dao层映射关联.还有一大推其它配置.当然Mybatis也发现了这种弊端,初期开发了generator可以根据表结构自动生成实体类.配置文件和 ...

随机推荐

  1. [转帖]Oracle 如何列出正在运行的定时任务

    https://geek-docs.com/oracle/oracle-questions/569_oracle_how_can_i_list_the_scheduled_jobs_running_i ...

  2. [转帖]5、kafka监控工具Kafka-Eagle介绍及使用

    https://zhuanlan.zhihu.com/p/628039102   # Apache Kafka系列文章 1.kafka(2.12-3.0.0)介绍.部署及验证.基准测试 2.java调 ...

  3. [转帖]Linux系统下cpio命令详解

    简介 cpio主要是解压或者将文件压缩到指定文件中即copy-in和copy-out模式. 参数说明 参数 参数说明 -i copy-in模式,解压文件 -o copy-out模式,即压缩文件 -d ...

  4. 解锁前端新潜能:如何使用 Rust 锈化前端工具链

    ​ 前言 近年来,Rust的受欢迎程度不断上升.首先,在操作系统领域,Rust 已成为 Linux 内核官方认可的开发语言之一,Windows 也宣布将使用 Rust 来重写内核,并重写部分驱动程序. ...

  5. ElementUI实现表格(table) 行上下移动的效果

    参考地址 https://blog.csdn.net/sunshine0508/article/details/88390155 看大佬的地址 <div id="app"&g ...

  6. RabbitMQ集成系统文章01---ABP VNext 分布式事务Event Bus 集成RabbitMQ

    1.在两个应用中都配置好要连接的RabbitMQ "RabbitMQ": { "Connections": { "Default": { & ...

  7. HTML超链接自定义颜色

    先添加一个css样式 我这里直接内嵌了因为代码量比较少不会影响太大的性能 <style type="text/css"> body {background-color: ...

  8. vim 从嫌弃到依赖(9)——命令模式进阶

    上一篇文章更新还是在51前,最近发生了很多事情了,全国各地的疫情又有蔓延的趋势,北京朝阳区都已经开始实施居家办公.各位小伙伴请注意安全,安全平安的度过这个疫情. 废话不多说了,接着上次的内容往下写. ...

  9. TienChin 渠道管理-渠道搜索

    ChannelController @PreAuthorize("hasPermission('tienchin:channel:list')") @GetMapping(&quo ...

  10. 《Mybatis 手撸专栏》第2章:创建简单的映射器代理工厂

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 着急和快,是最大的障碍! 慢下来,慢下来,只有慢下来,你才能看到更全的信息,才能学到 ...