Spring Boot 条件生效

最近做一个功能,其中涉及条件开启关闭,即在某些条件下功能是启用的,在其他条件下功能需要禁用。想到了之前看 Spring Boot 文档里条件生效 @ConditionalOnProperty 注解,于是便拿来用了用发现效果还不错,于是写一篇日志记录下。

需求定义

当前有一MQ功能,需要在MQ连接配置时收发消息,其他未配置属性的机器不做处理。这里便涉及两点:

  • 禁用默认启用的 AutoConfiguration
  • 使用 @ConditionalOnxxxx 在特定的条件下启用相关功能

禁用自启动

根据 2.x 版本的文档可知 Spring Boot 在启动时会读取 jar 下的 META-INF/spring.factories 相关配置,针对 RabbitAutoConfiguration 的配置可以在 spring-boot-autoconfigure-2.x.xx.jar!\META-INF\spring.factories 中找到,位于 org.springframework.boot.autoconfigure.EnableAutoConfiguration 配置列表中,这样在 Spring Boot 启动过程中就会自动装配启用 RabbitAutoConfiguration 相关的功能

那么如何禁用自启动呢? 使用@SpringBootApplication(exclude = RabbitAutoConfiguration.class) 即可禁用对应的MQ自动装配功能,当然如果你能做到差异化构建部署包也可以直接排除相关 jar 利用其自身 @ConditionalOnClass({ RabbitTemplate.class, Channel.class }) 的条件启动来物理屏蔽也是可以的,用构建屏蔽 jar 会带来部署上的成本,所以我没有采用这种方式。

使用 @ConditionalOnxxxx,

在前面我们已经禁用了相关的自动装配功能,那么如何在特定条件下启用相关功能呢?这里我采用的ConditionalOnExpression注解,该注解可以按 Spring EL 表达式来处理条件。

这里不使用常规的 @Component 等配置注解,因为这种方式不如@Configuration@Bean 组合来灵活配置容器实例, 以下是一个示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Configuration
@Import(RabbitAutoConfiguration.class)
// 未定义 RABBITMQ_URL 的机器不启用功能
@ConditionalOnExpression(value = "!'${RABBITMQ_URL:}'.trim().isEmpty()")
public class XxxxConfiguration {
/**
* 应用服务
*/
@Bean
XxxxApplication xxxxApplication(ControlAmqp amqp) {
return new XxxxApplication(amqp);
}

/**
* API入口
*/
@Bean
XxxxController xxxxApplication() {
return new XxxxController();
}
}

可以看到在这个 Configuration 中定义了两个 Bean, 一个是Web服务,另一个则是应用服务,只有当环境变量中存在 RABBITMQ_URL 且值不为空时才会启用这这两个 Bean 同时会导入 RabbitAutoConfiguration.class 配置,使整个服务生效。

当然还有其他的一些条件注解@ConditionalOnXxxx,诸如 @ConditionalOnClass 当依赖中存在相关 Class 时才会生效装配此实例等等,限于精力就不做一一介绍,有兴趣的可以自行查看源码学习了解。

写在最后

其实这个小知识点篇幅不大,本来不打算记录的,但是后来想想好记性不如烂笔头,还是写下来记录下,也许能帮到同样有需求的人。