玩转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的自动配置类:

properties 复制代码
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。以下是一个示例:

java 复制代码
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。例如:

java 复制代码
@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注解:

java 复制代码
@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、中间件、架构设计、面试题、程序员攻略等

相关推荐
柏油6 小时前
MySQL InnoDB 行锁
数据库·后端·mysql
咖啡调调。6 小时前
使用Django框架表单
后端·python·django
白泽talk6 小时前
2个小时1w字| React & Golang 全栈微服务实战
前端·后端·微服务
摆烂工程师6 小时前
全网最详细的5分钟快速申请一个国际 “edu教育邮箱” 的保姆级教程!
前端·后端·程序员
一只叫煤球的猫6 小时前
你真的会用 return 吗?—— 11个值得借鉴的 return 写法
java·后端·代码规范
Asthenia04127 小时前
HTTP调用超时与重试问题分析
后端
颇有几分姿色7 小时前
Spring Boot 读取配置文件的几种方式
java·spring boot·后端
AntBlack7 小时前
别说了别说了 ,Trae 已经在不停优化迭代了
前端·人工智能·后端
@淡 定7 小时前
Spring Boot 的配置加载顺序
java·spring boot·后端