关于 Spring 配置类的 Configurer 模式
- 前言
- demo
- SampleComponent
- SampleComponentConfigurer
- AbstractSampleComponentConfiguration
- SampleComponentConfiguration
- TestDemo
- 小结
- Spring Async
- ProxyAsyncConfiguration
- AbstractAsyncConfiguration
- AsyncConfigurer
- demo
- Spring Cache
- ProxyCachingConfiguration
- AbstractCachingConfiguration
- CachingConfigurer
- demo
- 总结
前言
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();
}
// getter & setter ...
}
- 模拟一个核心组件
-
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;
/**
* 基于自定义提供的 SampleComponentConfigurer 来配置对应属性
*/
@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);
}
// Supplier<SampleComponentConfigurer> 到 Supplier<T> 的映射,T 即属性类型
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();
// 基于 SampleComponentConfigurer 进行配置
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
AsyncAnnotationBeanPostProcessor bpp = new AsyncAnnotationBeanPostProcessor();
// 基于 AsyncConfigurer 自定义配置属性
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;
// ...
// 获取容器中的 AsyncConfigurer
@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);
});
// 如果有且仅有一个 AsyncConfigurer 实例,则从中解析 executor 和 exceptionHandler
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 {
/**
* 自定义 Spring Async 任务执行的线程池
*/
@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();
/**
* 基于 CacheConfigurer 自定义配置属性
*/
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) {
// 收集容器中用户定义的所有 CachingConfigurer
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);
};
// 基于提供的 CachingConfigurer 对属性进行配置
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);
}
// 内部类协助 CachingConfigurer 的处理
protected static class CachingConfigurerSupplier {
private final Supplier<CachingConfigurer> supplier;
public CachingConfigurerSupplier(Supplier<CachingConfigurer> supplier) {
this.supplier = SingletonSupplier.of(supplier);
}
// CachingConfigurer 到属性的映射
@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 {
/**
* 管理对应的 Cache 集合
*/
@Nullable
default CacheManager cacheManager() {
return null;
}
/**
* 用来解析对应的 Cache,通常基于 CacheManager
*/
@Nullable
default CacheResolver cacheResolver() {
return null;
}
/**
* 用来生成缓存 key
*/
@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 {
// 注册 ConcurrentMapCacheManager
@Bean
@Override
public CacheManager cacheManager() {
ConcurrentMapCacheManager cacheManager
= new ConcurrentMapCacheManager();
return cacheManager;
}
}
-
Spring Cache
的配置类 - 指定了缺省的
CacheManager
- 注册为
bean
组件是为了让Spring
管理CacheManager
的生命周期
总结
优秀的 自定义回调处理配置
案例,示例 demo
结合 Spring
的应用可以更加深入的了解,希望对开发工作有帮助