Spring Boot 优雅回调工具类 LambdaSafe
前言
发现了 Spring Boot
一个处理回调的工具类,做个分享
LambdaSafe
LambdaSafeCallback
/**
* 回调处理基类
*/
protected abstract static class LambdaSafeCallback<C, A, SELF extends LambdaSafeCallback<C, A, SELF>> {
// 回调类型
private final Class<C> callbackType;
// 被回调实例
private final A argument;
private Log logger;
// 过滤器,默认 GenericTypeFilter
private Filter<C, A> filter = new GenericTypeFilter<>();
LambdaSafeCallback(Class<C> callbackType, A argument, Object[] additionalArguments) {
this.callbackType = callbackType;
this.argument = argument;
this.additionalArguments = additionalArguments;
this.logger = LogFactory.getLog(callbackType);
}
// logger 构造器
public SELF withLogger(Class<?> loggerSource) {
return withLogger(LogFactory.getLog(loggerSource));
}
// logger 构造器
public SELF withLogger(Log logger) {
this.logger = logger;
return self();
}
// filter 构造器
SELF withFilter(Filter<C, A> filter) {
this.filter = filter;
return self();
}
// InvocationResult:封装回调接口(如果有的话)
protected final <R> InvocationResult<R> invoke(C callbackInstance, Supplier<R> supplier) {
// 如果过滤器通过(泛型匹配)就执行回调
if (this.filter.match(this.callbackType, callbackInstance, this.argument, this.additionalArguments)) {
try {
return InvocationResult.of(supplier.get());
}
catch (ClassCastException ex) {
// ...
}
}
return InvocationResult.noResult();
}
// ...
}
- 回调处理的抽象基类
LambdaSafeCallback
,这是一个内部类(高内聚的体现) - 主要是
invoke
逻辑,它在执行回调方法前会经过Filter
的过滤,默认实例是GenericTypeFilter
Callback
public static final class Callback<C, A> extends LambdaSafeCallback<C, A, Callback<C, A>> {
private final C callbackInstance;
// 私有构造
private Callback(Class<C> callbackType, C callbackInstance, A argument, Object[] additionalArguments) {
super(callbackType, argument, additionalArguments);
this.callbackInstance = callbackInstance;
}
// 指定回调 Consumer,没有返回值
public void invoke(Consumer<C> invoker) {
invoke(this.callbackInstance, () -> {
invoker.accept(this.callbackInstance);
return null;
});
}
// ...
}
LambdaSafeCallback
的内部类实现- 构造方法私有化,由
LambdaSafe
暴露出去,见后文 - 指定对应的
Consumer
,由super.invoke
调用,Consumer
就对应的回调逻辑比如Costomizer::costumize
Callbacks
// Callback 的复数版本
public static final class Callbacks<C, A> extends LambdaSafeCallback<C, A, Callbacks<C, A>> {
private final Collection<? extends C> callbackInstances;
private Callbacks(Class<C> callbackType, Collection<? extends C> callbackInstances, A argument,
Object[] additionalArguments) {
super(callbackType, argument, additionalArguments);
this.callbackInstances = callbackInstances;
}
// ...
}
Callback
的复数版本,Spring
常用的设计模式,可以理解为组合模式(composite)
Filter
@FunctionalInterface
interface Filter<C, A> {
/**
* 基于回调器类型、回调器实例、被回调实例解析过滤
*/
boolean match(Class<C> callbackType, C callbackInstance, A argument, Object[] additionalArguments);
/**
* 静态方法,提供一个 all true 的实例
*/
static <C, A> Filter<C, A> allowAll() {
return (callbackType, callbackInstance, argument, additionalArguments) -> true;
}
}
- 内部类函数式接口
- 主要是对回调方法的执行进行过滤
GenericTypeFilter
// 对泛型的匹配过滤
private static class GenericTypeFilter<C, A> implements Filter<C, A> {
@Override
public boolean match(Class<C> callbackType, C callbackInstance, A argument, Object[] additionalArguments) {
// 解析对应回调器上指定的泛型
ResolvableType type = ResolvableType.forClass(callbackType, callbackInstance.getClass());
// 如果指定了泛型则解析出来必须与被回调类一致
if (type.getGenerics().length == 1 && type.resolveGeneric() != null) {
return type.resolveGeneric().isInstance(argument);
}
return true;
}
}
Filter
接口的内部类实现- 主要逻辑就是对
泛型
的校验,比如Customizer<Specific>
指定了处理回调的类型为Specific
,则传入的argument
类型就必须是Specific
,如果没指定或者制定了多个泛型等,默认返回true
LambdaSafe
// 返回一个 Callback 实例
public static <C, A> Callback<C, A> callback(Class<C> callbackType, C callbackInstance, A argument,
Object... additionalArguments) {
return new Callback<>(callbackType, callbackInstance, argument, additionalArguments);
}
// 返回一个 Callbacks 实例
public static <C, A> Callbacks<C, A> callbacks(Class<C> callbackType, Collection<? extends C> callbackInstances,
A argument, Object... additionalArguments) {
return new Callbacks<>(callbackType, callbackInstances, argument, additionalArguments);
}
- 基于前面的铺垫,
LambdaSafe
暴露静态方法用于获取对应的Callback
Callbacks
实例 - 具体回调逻辑基于
invoke
方法实现
示例
Customizer
@FunctionalInterface
public interface Customizer<T> {
void customize(T instance);
}
很眼熟的 Customizer
回调处理类,对 T
类型的实例进行回调处理
HelloService
public class HelloService {
public void callback() {
System.out.println("hello");
}
}
被回调测试类,回调方法为 callback
TestMain
public class TestMain {
@Test
public void test() {
HelloService instance = new HelloService();
Customizer<HelloService> customizer = HelloService::callback;
// 必须指定正确的泛型与 instance 匹配
// Customizer<LambdaSafe> customizer = t -> {};
LambdaSafe.callback(
Customizer.class
, customizer
, instance
, null
)
.invoke(customizer1 -> customizer1.customize(instance));
}
}
基于 LambdaSafe.Callback
实例的优雅回调
Spring Boot 使用案例
public class CacheManagerCustomizers {
// 所有用户注册的 CacheManagerCustomizer
private final List<CacheManagerCustomizer<?>> customizers;
public CacheManagerCustomizers(List<? extends CacheManagerCustomizer<?>> customizers) {
this.customizers = (customizers != null) ? new ArrayList<>(customizers) : Collections.emptyList();
}
@SuppressWarnings("unchecked")
// 基于 LambdaSafe.Callbacks 的优雅回调
public <T extends CacheManager> T customize(T cacheManager) {
LambdaSafe.callbacks(CacheManagerCustomizer.class, this.customizers, cacheManager)
.withLogger(CacheManagerCustomizers.class).invoke((customizer) -> customizer.customize(cacheManager));
return cacheManager;
}
}
- 这是
Spring Boot
对Spring Cache
的自动装配支持 - 此类会基于用户注册的所有
CacheManagerCustomizer
对容器中的cacheManager
实例进行回调处理 - 使用了
LambdaSafe.Callbacks
的优雅回调
总结
Spring Boot
大佬封装的小而美的工具类,用起来