关于 Spring 配置类的 Configurer 模式
前言
Spring 作为拓展性做到极致的工程,对核心功能组件的配置都支持用户的自定义拓展,其中一种常见的模式就是 Configurer 回调配置,比如 AsyncConfigurer CacheConfigurer 等类
本文从一个简单的模拟示例入手,再借助 Spring 的应用协助理解一下这种模式
demo
SampleComponent
public class SampleComponent {
private String name;
private Integer age;
public void configurer(Supplier<String> name, Supplier<Integer> age) {
this.name = name.get();
this.age = age.get();
}
}
- 模拟一个核心组件
configurer 方法支持自定义组件属性
SampleComponentConfigurer
public interface SampleComponentConfigurer {
default String getName() {
return "default";
}
default Integer getAge() {
return 18;
}
}
- 这是针对
SampleComponent 的 Configurer 回调配置接口 - 它可以通过覆盖方法的形式来自定义
SampleComponent 组件的属性
AbstractSampleComponentConfiguration
@Configuration
public abstract class AbstractSampleComponentConfiguration {
Supplier<String> name;
Supplier<Integer> age;
@Autowired
public void setConfigurer(ObjectProvider<SampleComponentConfigurer> configurers) {
List<SampleComponentConfigurer> configurerList =
configurers.stream().collect(Collectors.toList());
Supplier<SampleComponentConfigurer> supplier = () -> {
if (CollectionUtils.isEmpty(configurerList)) {
return null;
}
if (configurerList.size() > 1) {
throw new RuntimeException("只允许指定一个 SampleComponentConfigurer");
}
return configurerList.get(0);
};
name = adapt(supplier, SampleComponentConfigurer::getName);
age = adapt(supplier, SampleComponentConfigurer::getAge);
}
private <T> Supplier<T> adapt(Supplier<SampleComponentConfigurer> supplier
, Function<SampleComponentConfigurer, T> function) {
return () -> {
SampleComponentConfigurer sampleComponentConfigurer = supplier.get();
return sampleComponentConfigurer == null ? null : function.apply(sampleComponentConfigurer);
};
}
}
- 这种自定义回调配置行为通常由基类定义
- 它收集用户提供的
SampleComponentConfigurer 配置类(通常只允许一个),然后基于此获取指定的对应属性 adapt 方法从 SampleComponentConfigurer 中提取对应的属性- 知识点:
@Autowired 注解的方法在属性后处理阶段执行ObjectProvider 类型的返回值会包装对应的所有 bean 组件
SampleComponentConfiguration
@Configuration
public class SampleComponentConfiguration extends AbstractSampleComponentConfiguration {
@Bean
public SampleComponent sampleComponent() {
SampleComponent sampleComponent = new SampleComponent();
sampleComponent.configurer(name, age);
return sampleComponent;
}
}
- 模拟针对功能组件的配置,这种配置类一般都是框架提供的,基于
Import 等机制引入 - 因此我们可以在不修改配置类的情况下提供自己的
SampleComponentConfigurer 来配置组件
TestDemo
public class TestDemo {
@Configuration
@Import({ SampleComponentConfiguration.class })
public static class Config implements SampleComponentConfigurer {
@Override
public String getName() {
return "dd";
}
}
@Test
public void test() {
AnnotationConfigApplicationContext applicationContext
= new AnnotationConfigApplicationContext(Config.class);
SampleComponent bean = applicationContext.getBean(SampleComponent.class);
System.out.println(bean.getName());
System.out.println(bean.getAge());
}
}
- 这里模拟应用场景,
@Import({ SampleComponentConfiguration.class }) 功能一般以类似 @EnableXXX 的模式提供 - 我们提供的配置类
Config 实现 SampleComponentConfigurer 接口以支持组件属性的自定义配置 - 示例中,我们覆盖了
SampleComponent 的 name 属性
小结
可以看到,在真正的应用场景中(TestDemo ),我们只需要提供一个 SampleComponentConfigurer 就可以自定义组件的属性(而不是自己注册一个组件来覆盖)
这符合 对修改关闭,对拓展开方 的原则
Spring Async
ProxyAsyncConfiguration
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyAsyncConfiguration extends AbstractAsyncConfiguration {
@Bean(name = TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public AsyncAnnotationBeanPostProcessor asyncAdvisor() {
AsyncAnnotationBeanPostProcessor bpp = new AsyncAnnotationBeanPostProcessor();
bpp.configure(this.executor, this.exceptionHandler);
return bpp;
}
}
- 该类由
@EnableAsync 引入 - 可以看到它在注册
AsyncAnnotationBeanPostProcessor 时会基于 configure 方法进行自定义配置 - 此处的
AsyncAnnotationBeanPostProcessor 就相当于之前示例中的 SampleComonent ProxyAsyncConfiguration 类就相当于之前示例中的 SampleComponentConfiguration
AbstractAsyncConfiguration
@Configuration(proxyBeanMethods = false)
public abstract class AbstractAsyncConfiguration implements ImportAware {
@Nullable
protected Supplier<Executor> executor;
@Nullable
protected Supplier<AsyncUncaughtExceptionHandler> exceptionHandler;
@Autowired
void setConfigurers(ObjectProvider<AsyncConfigurer> configurers) {
Supplier<AsyncConfigurer> configurer = SingletonSupplier.of(() -> {
List<AsyncConfigurer> candidates = configurers.stream().collect(Collectors.toList());
if (CollectionUtils.isEmpty(candidates)) {
return null;
}
if (candidates.size() > 1) {
throw new IllegalStateException("Only one AsyncConfigurer may exist");
}
return candidates.get(0);
});
this.executor = adapt(configurer, AsyncConfigurer::getAsyncExecutor);
this.exceptionHandler = adapt(configurer, AsyncConfigurer::getAsyncUncaughtExceptionHandler);
}
private <T> Supplier<T> adapt(Supplier<AsyncConfigurer> supplier, Function<AsyncConfigurer, T> provider) {
return () -> {
AsyncConfigurer configurer = supplier.get();
return (configurer != null ? provider.apply(configurer) : null);
};
}
}
- 它就是
ProxyAsyncConfiguration 的配置基类,相当于之前示例中的 AbstractSampleComponentConfiguration - 具体的细节跟示例如出一辙,就是支持基于
AsyncConfigurer 的自定义配置属性
AsyncConfigurer
public interface AsyncConfigurer {
@Nullable
default Executor getAsyncExecutor() {
return null;
}
@Nullable
default AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return null;
}
}
- 自定义配置回调处理类,相当于之前示例中的
SampleComponentConfigurer - 此处支持
AsyncAnnotationBeanPostProcessor 的属性自定义配置
demo
@EnableAsync
@Configuration
public class AsyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
return new ThreadPoolExecutor(
2
, 4
, 10
, TimeUnit.SECONDS
, new LinkedBlockingQueue<>()
);
}
}
Spring Async 的配置类- 实现
AsyncConfigurer 接口覆盖 getAsyncExecutor 方法为异步任务指定默认的 Executor
Spring Cache
ProxyCachingConfiguration
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyCachingConfiguration extends AbstractCachingConfiguration {
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public CacheInterceptor cacheInterceptor(CacheOperationSource cacheOperationSource) {
CacheInterceptor interceptor = new CacheInterceptor();
interceptor.configure(this.errorHandler, this.keyGenerator, this.cacheResolver, this.cacheManager);
interceptor.setCacheOperationSource(cacheOperationSource);
return interceptor;
}
}
如出一辙,支持 CacheInterceptor 的自定义配置
AbstractCachingConfiguration
@Configuration(proxyBeanMethods = false)
public abstract class AbstractCachingConfiguration implements ImportAware {
@Nullable
protected Supplier<CacheManager> cacheManager;
@Nullable
protected Supplier<CacheResolver> cacheResolver;
@Nullable
protected Supplier<KeyGenerator> keyGenerator;
@Nullable
protected Supplier<CacheErrorHandler> errorHandler;
@Autowired
void setConfigurers(ObjectProvider<CachingConfigurer> configurers) {
Supplier<CachingConfigurer> configurer = () -> {
List<CachingConfigurer> candidates = configurers.stream().collect(Collectors.toList());
if (CollectionUtils.isEmpty(candidates)) {
return null;
}
if (candidates.size() > 1) {
throw new IllegalStateException("...");
}
return candidates.get(0);
};
useCachingConfigurer(new CachingConfigurerSupplier(configurer));
}
protected void useCachingConfigurer(CachingConfigurerSupplier cachingConfigurerSupplier) {
this.cacheManager = cachingConfigurerSupplier.adapt(CachingConfigurer::cacheManager);
this.cacheResolver = cachingConfigurerSupplier.adapt(CachingConfigurer::cacheResolver);
this.keyGenerator = cachingConfigurerSupplier.adapt(CachingConfigurer::keyGenerator);
this.errorHandler = cachingConfigurerSupplier.adapt(CachingConfigurer::errorHandler);
}
protected static class CachingConfigurerSupplier {
private final Supplier<CachingConfigurer> supplier;
public CachingConfigurerSupplier(Supplier<CachingConfigurer> supplier) {
this.supplier = SingletonSupplier.of(supplier);
}
@Nullable
public <T> Supplier<T> adapt(Function<CachingConfigurer, T> provider) {
return () -> {
CachingConfigurer cachingConfigurer = this.supplier.get();
return (cachingConfigurer != null ? provider.apply(cachingConfigurer) : null);
};
}
}
}
- 配置基类,提供基于
CacheConfigurer 配置的方法 - 实现细节稍有不同,但逻辑一样
CachingConfigurer
public interface CachingConfigurer {
@Nullable
default CacheManager cacheManager() {
return null;
}
@Nullable
default CacheResolver cacheResolver() {
return null;
}
@Nullable
default KeyGenerator keyGenerator() {
return null;
}
@Nullable
default CacheErrorHandler errorHandler() {
return null;
}
}
- 自定义回调配置类
- 支持
Spring Cache 的组件 CacheInterceptor 的 cacheManager cacheResolver keyGenerator errorHandler 属性的配置 - 上述属性的优先级低于缓存注解上的指定,可以理解为缺省属性
demo
@Configuration
@EnableCaching
public class CacheConfig implements CachingConfigurer {
@Bean
@Override
public CacheManager cacheManager() {
ConcurrentMapCacheManager cacheManager
= new ConcurrentMapCacheManager();
return cacheManager;
}
}
Spring Cache 的配置类- 指定了缺省的
CacheManager - 注册为
bean 组件是为了让 Spring 管理 CacheManager 的生命周期
总结
优秀的 自定义回调处理配置 案例,示例 demo 结合 Spring 的应用可以更加深入的了解,希望对开发工作有帮助
|