背景
Spring Boot Starters 提供了很多常用的组件,有些组件例如 Kafka
和 RocketMQ
,引入到工程后会自动装配,它会检查您的配置,跟外部的组件创建一些连接,这个时候,我们很难控制 Kafka
关闭,RocketMQ
开启。
目标
给 Spring Boot Starters 的组件提供一个开关,控制自动装配。
实现
Spring Boot AutoCofiguration 提供了 AutoConfigurationImportFilter
过滤器,用来控制 @Configuration
配置类是否生效。查看 AutoConfigurationImportSelector
的源码,它会去调用 AutoConfigurationImportFilter
过滤器,传入所有的 @Configuration
配置类,通过 filter 方法筛选掉不需要的配置类,返回最新的配置类集合。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered { private static class ConfigurationClassFilter {
private final AutoConfigurationMetadata autoConfigurationMetadata;
private final List<AutoConfigurationImportFilter> filters;
ConfigurationClassFilter(ClassLoader classLoader, List<AutoConfigurationImportFilter> filters) { this.autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(classLoader); this.filters = filters; }
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } configurations = getConfigurationClassFilter().filter(configurations); fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry(configurations, exclusions); }
List<String> filter(List<String> configurations) { long startTime = System.nanoTime(); String[] candidates = StringUtils.toStringArray(configurations); boolean skipped = false; for (AutoConfigurationImportFilter filter : this.filters) { boolean[] match = filter.match(candidates, this.autoConfigurationMetadata); for (int i = 0; i < match.length; i++) { if (!match[i]) { candidates[i] = null; skipped = true; } } } if (!skipped) { return configurations; } } } }
|
以 Kafka 为例,我们可以在 src/main/resources/META-INF
添加 spring.factories
文件,内容如下:
1 2 3
| org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\ org.ylzl.spring.boot.kafka.autoconfigure.KafkaAutoConfigurationImportFilter
|
对应的代码实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| public class KafkaAutoConfigurationImportFilter implements AutoConfigurationImportFilter, EnvironmentAware {
private static final String MATCH_KEY = "spring.kafka.enabled";
private static final String[] IGNORE_CLASSES = { "org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration", "org.springframework.boot.actuate.autoconfigure.metrics.KafkaMetricsAutoConfiguration" };
private Environment environment;
@Override public void setEnvironment(@NotNull Environment environment) { this.environment = environment; }
@Override public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) { boolean disabled = !Boolean.parseBoolean(environment.getProperty(MATCH_KEY, Conditions.TRUE)); boolean[] match = new boolean[autoConfigurationClasses.length]; for (int i = 0; i < autoConfigurationClasses.length; i++) { int index = i; match[i] = !disabled || Arrays.stream(IGNORE_CLASSES).noneMatch(e -> e.equals(autoConfigurationClasses[index])); } return match; } }
|
代码扩展完成,当设置 spring.kafka.enabled=true
时开启 Kafka,设置 spring.kafka.enabled=false
时关闭 Kafka。
产出
- 支持工程内同时存在多种竞品组件,允许您按需开启和关闭。
- 解决第三方组件自动装配的问题,例如第三方项目,一个依赖引入多项配置,这些配置我们用不到,又修改不了相关源码,需要从扩展点屏蔽。