玩转SpringBoot:动态排除Starter配置,轻松部署
引言
在软件开发中,进行本地单元测试是一项常规且必要的任务。然而,在进行单元测试时,有时需要启动一些中间件服务,如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.properties或application.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或应用某个配置。具体来说,@ConditionalOnProperty的name属性表示配置属性的名称,havingValue属性表示配置属性的期望值,默认为true,matchIfMissing属性表示当配置属性不存在时是否匹配条件,默认为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或者是否应该应用某个配置。一些常见的条件注解包括:
@ConditionalOnClass:当类路径中存在指定的类时,才会创建Bean或应用配置。@ConditionalOnMissingClass:当类路径中不存在指定的类时,才会创建Bean或应用配置。@ConditionalOnBean:当容器中存在指定的Bean时,才会创建Bean或应用配置。@ConditionalOnMissingBean:当容器中不存在指定的Bean时,才会创建Bean或应用配置。@ConditionalOnExpression:当满足SpEL表达式定义的条件时,才会创建Bean或应用配置。@ConditionalOnJava:当JVM运行的Java版本符合指定条件时,才会创建Bean或应用配置。@ConditionalOnWebApplication:当运行的环境是Web应用程序时,才会创建Bean或应用配置。@ConditionalOnNotWebApplication:当运行的环境不是Web应用程序时,才会创建Bean或应用配置。
总结
本文介绍了在Spring Boot项目中如何排除Starter自动配置类,以及根据不同环境动态排除配置的方法。通过spring.autoconfigure.exclude属性和条件注解如@ConditionalOnProperty,我们可以灵活控制Bean的创建和配置的应用,从而更好地适应不同的部署环境和需求。
本文已收录于我的个人博客:码农Academy的博客,专注分享Java技术干货,包括Java基础、Spring Boot、Spring Cloud、Mysql、Redis、Elasticsearch、中间件、架构设计、面试题、程序员攻略等
玩转SpringBoot:动态排除Starter配置,轻松部署的更多相关文章
- 【玩转SpringBoot】给自动配置来个整体大揭秘
上一篇文章中提到的条件注解,只是自动配置整体解决方案中的一个环节而已,可以说是管中窥豹. 本文就逐步擦除迷雾,让整体浮现出来,这样就会有一个宏观的认识. 除了写代码之外,还能干点什么? 提到“配置”这 ...
- 【玩转SpringBoot】异步任务执行与其线程池配置
同步代码写起来简单,但就是怕遇到耗时操作,会影响效率和吞吐量. 此时异步代码才是王者,但涉及多线程和线程池,以及异步结果的获取,写起来颇为麻烦. 不过在遇到SpringBoot异步任务时,这个问题就不 ...
- 【玩转SpringBoot】看似复杂的Environment其实很简单
喜欢写代码,讨厌配环境 我相信这十个字的小标题代表了大多数码农的心声. 十年前读大学时,学校开设了C语言还有C++.但是学习这两种语言,对于新手来说非常没有成就感. 于是我就在校门口买个光盘,装个VS ...
- 【玩转SpringBoot】翻身做主人,一统web服务器
寄人篱下的日子 一直以来受传统影响,我们的web工程总是打成war包,然后放入tomcat的webapps目录下面. 如下图01: 当tomcat启动时,会去解压war包,然后运行web工程.这大家都 ...
- 【玩转SpringBoot】让错误处理重新由web服务器接管
其实web服务器是会处理错误的 在web.xml还是随处可见的年代时(确实有点老黄历了),下面的这些配置应该都不陌生. 根据错误代码处理错误,如下图01: 根据异常类型处理错误,如下图02: 不过我们 ...
- 【玩转SpringBoot】通过事件机制参与SpringBoot应用的启动过程
生命周期和事件监听 一个应用的启动过程和关闭过程是归属到“生命周期”这个概念的范畴. 典型的设计是在启动和关闭过程中会触发一系列的“事件”,我们只要监听这些事件,就能参与到这个过程中来. 要想监听事件 ...
- 【玩转SpringBoot】SpringBoot应用的启动过程一览表
SpringBoot应用的启动方式很简单,就一行代码,如下图01: 其实这行代码背后主要执行两个方法,一个是构造方法,一个是run方法. 构造方法主要内容就是收集一些数据,和确认一些信息.如下图02: ...
- 【玩转SpringBoot】用好条件相关注解,开启自动配置之门
自动配置隐含两层含义,要搞清楚 上帝让程序员的发量减少,是为了让他变得更聪明,如果有一天聪明到了极点,那就是绝顶聪明. 据说在大脑高速运转下,这样更有利于散热,不至于核心温度过高而产生告警. 聪明的大 ...
- SpringBoot 动态配置邮箱发件人
SpringBoot 动态配置邮箱发件人 现在的消息模块少不了邮件发送.短信发送和手机推送的功能.邮件发送的功能历史最为悠久,也算的上烂大街的功能.一般在配置文件中设置好邮箱地址.账号.密码和发件服务 ...
- SpringBoot集成Mybatis(0配置注解版)
Mybatis初期使用比较麻烦,需要各种配置文件.实体类.dao层映射关联.还有一大推其它配置.当然Mybatis也发现了这种弊端,初期开发了generator可以根据表结构自动生成实体类.配置文件和 ...
随机推荐
- Oracle 专用模式与共享模式的学习与思考
Oracle 专用模式与共享模式的学习与思考 说明 Oracle数据库中的专用模式和共享模式是两种不同的数据库运行模式,它们在应用场景和权限管理上有所不同. 专用模式(Dedicated Mode): ...
- [转帖]Linux常用的一些命令,看你知道多少?
https://zhuanlan.zhihu.com/p/115279009 Linux中命令有很多,而Linux系统中使用命令也是它的一大特点.在Linux系统中使用命令处理问题灵活,高效,所以熟知 ...
- [转帖]Centos7 nginx访问日志文件割接
一.yum安装nginx 二.各文件路径( /etc/nginx/nginx.conf) 1.访问日志路径:access_log /var/log/nginx/access.log main; 2.p ...
- [转帖]Redis如何绑定CPU
文章系转载,便于分类和归纳,源文地址:https://www.yisu.com/zixun/672271.html 绑定 CPU Redis 6.0 开始支持绑定 CPU,可以有效减少线程上下文切换. ...
- 一个简单的监控java进程获取日志的办法
公司里面一个长时间运行的环境会出现问题, 这边简单写了一个脚本自动获取日志信息 脚本如下 注意 我的path 其实就是复用的 我们应用里面的jdk 剩下的就非常简单了. 每个日志都自动打包 并且移除 ...
- 基于javaPoet的缓存key优化实践
一. 背景 在一次系统opsreview中,发现了一些服务配置了@Cacheable注解.@cacheable 来源于spring cache框架中,作用是使用aop的方式将数据库中的热数据缓存在re ...
- @Transaction注解的失效场景
作者:京东物流 孔祥东 背景 事情是这样,最近在实现一个需求的时候,有一个定时异步任务会捞取主表的数据并置为处理中(为了防止任务执行时间过长,下次任务执行把本次数据重复捞取),然后根据主表关联明细表数 ...
- 【K哥爬虫普法】百度、360八年恩怨情仇,robots 协议之战终落幕
我国目前并未出台专门针对网络爬虫技术的法律规范,但在司法实践中,相关判决已屡见不鲜,K哥特设了"K哥爬虫普法"专栏,本栏目通过对真实案例的分析,旨在提高广大爬虫工程师的法律意识,知 ...
- TienChin 活动管理-活动状态完善
修改字典 修改活动状态字典,将之前的数据键值为 0 的数据标签内容改为 过期: 更改下数据库的描述,禁用改为过期: ALTER TABLE `tienchin_activity` MODIFY COL ...
- net8来了
11 月 15 日开始的为期三天的 .NET Conf 在线活动的开幕日上,.NET 8作为微软的开源跨平台开发平台正式发布..NET 团队着重强调云.性能.全栈 Blazor.AI 和 .NET M ...