本文共 1913 字,大约阅读时间需要 6 分钟。
使用设计模式:动态代理,方法链
1.InterceptorChain 拦截链
通过方法链的模式,层层包装拦截对象,
pluginAll 通过for循环一次次封装对象,
addInterceptor 添加拦截器 要在pluginAll 之前调用才有效
getInterceptors 获取所有的拦截器
2.Interceptor 拦截器接口
intercept 拦截方法 在次方法内可以对拦截目标进行特殊处理
setProperties 通过此方法可以将配置文件中的属性设置到拦截器中
plugin 打包拦截对象 通过Plugin.wrap ->动态代理
eg:PluginTest
@Intercepts({
@Signature(type = Map.class, method = "get", args = {Object.class})})
public static class AlwaysMapPlugin implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws InvocationTargetException, IllegalAccessException {
System.out.println("拦截到了方法:" + invocation.getMethod() + "\n 参数:"+invocation.getArgs().toString() + "\n 被拦截对象:" + invocation.getTarget());
//调用原有逻辑通过invocation.proceed()
return invocation.proceed();
}
}
@Intercepts 标名此类是一个拦截器
@Signature 标名拦截的类与方法
type 拦截的类
method 拦截的方法
args 拦截的参数
因为JAVA重载的存在,所以需要类+方法+参数才能确认拦截的方法
3.Invocation 封装调用对象的过程(即封装method.invoke(obj,args))
4.Plugin 插件核心类 通过此类实现对代理对象的封装,
这里使用的动态代理模式是JDK模式
wrap 包装对象,方法
//包装目标对象
public static Object wrap(Object target, Interceptor interceptor) {
//获取拦截器可以拦截的所有类和方法
Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
Class<?> type = target.getClass();
//根据拦截器信息和当前目标的类型 取出所有可供拦截的接口
Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
//如果当前对象可以被拦截 那么生成一个代理对象
if (interfaces.length > 0) {
//获取代理对象
return Proxy.newProxyInstance(
type.getClassLoader(),
interfaces,
new Plugin(target, interceptor, signatureMap));
}
return target;
}
invoke 执行方法
/**
* 根据拦截对象的类获取可供拦截的方法
*/
Set<Method> methods = signatureMap.get(method.getDeclaringClass());
if (methods != null && methods.contains(method)) {
//执行拦截器的方法
return interceptor.intercept(new Invocation(target, method, args));
}
//执行普通调用
return method.invoke(target, args);
getSignatureMap 解析类上的注解 获取拦截信息
总结:插件模块使用了方法链 + 动态代理 实现了代码的高可用,如果需要新增一个拦截器,不用关注主体流程,直接在类上加注解和标明需要拦截的类方法即可实现拦截功能;符合单一职责原则,每个类各司其职 如果自己的业务上有这种需求 也可以直接挪过来使用,有很好的拓展性
转载地址:http://drnvi.baihongyu.com/