前言
-
这个系列主要讲优秀的开源框架对于责任链这个设计模式的运用,对于好的设计,我们关键是学习他的思想并运用在我们的编码中。
-
这个系列的所有代码都是我根据源码提炼之后的代码,不依赖原项目或框架,可以直接跑。
-
我不会讲每个具体是如何实现的,如果你觉得光看代码比较吃力,那么可以将代码复制下来,自己多运行几遍,我相信你一定能掌握,所以主打一个动手能力。
-
欢迎访问我的个人网站,里面有超多开源组件和项目,另外还有付费项目和博客,地址:https://openbytecode.com/
-
前三个小节主要介绍了 Tomcat 的 Filter 设计、SpringMVC 的 Interceptor 设计、 Spring 中 AOP 的设计,本小节主要讲 Mybatis 的 Plugin 设计。
-
本系列 Github 地址:https://github.com/lijunping365/Open-Design
Mybatis 之 Plugin
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({})
public @interface Signature {
/**
* Returns the java type.
*
* @return the java type
*/
Class<?> type();
/**
* Returns the method name.
*
* @return the method name
*/
String method();
/**
* Returns java types for method argument.
*
* @return java types for method argument
*/
Class<?>[] args();
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Intercepts {
/**
* Returns method signatures to intercept.
*
* @return method signatures
*/
Signature[] value();
}
public interface Interceptor {
Object intercept(Invocation invocation) throws Throwable;
default Object plugin(Object target) {
return Plugin.wrap(target, this);
}
}
public class Invocation {
private final Object target;
private final Method method;
private final Object[] args;
public Invocation(Object target, Method method, Object[] args) {
this.target = target;
this.method = method;
this.args = args;
}
public Object getTarget() {
return target;
}
public Method getMethod() {
return method;
}
public Object[] getArgs() {
return args;
}
public Object proceed() throws InvocationTargetException, IllegalAccessException {
return method.invoke(target, args);
}
}
public class Plugin implements InvocationHandler {
private final Object target;
private final Interceptor interceptor;
private final Map<Class<?>, Set<Method>> signatureMap;
private Plugin(Object target, Interceptor interceptor, Map<Class<?>, Set<Method>> signatureMap) {
this.target = target;
this.interceptor = interceptor;
this.signatureMap = signatureMap;
}
/**
* 包装代理
*
* @param interceptor 拦截器
*/
public static Object wrap(Object t, Interceptor interceptor) {
Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
return Proxy.newProxyInstance(
t.getClass().getClassLoader(),
t.getClass().getInterfaces(),
new Plugin(t, interceptor, signatureMap));
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
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);
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}
private static Map<Class<?>, Set<Method>> getSignatureMap(Interceptor interceptor) {
Intercepts interceptsAnnotation = interceptor.getClass().getAnnotation(Intercepts.class);
// 检查类是否被@Intercepts标记
if (interceptsAnnotation == null) {
throw new RuntimeException("No @Intercepts annotation was found in interceptor " + interceptor.getClass().getName());
}
Signature[] sings = interceptsAnnotation.value();
Map<Class<?>, Set<Method>> signatureMap = new HashMap<>();
// 检查被@Signature标记的方法是否存在
for (Signature sig : sings) {
Set<Method> methods = signatureMap.computeIfAbsent(sig.type(), k -> new HashSet<>());
try {
Method method = sig.type().getMethod(sig.method(), sig.args());
methods.add(method);
} catch (NoSuchMethodException e) {
throw new RuntimeException("Could not find method on " + sig.type() + " named " + sig.method() + ". Cause: " + e, e);
}
}
return signatureMap;
}
}
public class InterceptorChain {
/**
* 拦截器集合
*/
private final List<Interceptor> interceptors = new ArrayList<>();
/**
* 装载拦截器
*/
public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target);
}
return target;
}
/**
* 添加拦截器
*
* @param interceptor 拦截器
*/
public void addInterceptor(Interceptor interceptor) {
interceptors.add(interceptor);
}
/**
* 获取所有拦截器
*
* @return 拦截器集合
*/
public List<Interceptor> getInterceptors() {
return Collections.unmodifiableList(interceptors);
}
}
测试
public interface Download {
String download(String request);
}
public class SimpleDownload implements Download{
@Override
public String download(String request) {
System.out.println("执行了下载");
return "dddddddddddddddddddddddddd";
}
}
public interface Parser {
Map<String, String> parse(String response);
}
public class SimpleParser implements Parser{
@Override
public Map<String, String> parse(String response) {
System.out.println("执行解析");
Map<String, String> map = new HashMap<>();
map.put("key", response);
map.put("value", response);
return map;
}
}
拦截器
@Intercepts({@Signature(type = Download.class,method = "download",args = {String.class})})
public class DownloadPlugin implements Interceptor {
/**
* 这个方法会直接覆盖原有方法
* @param invocation
* @return
* @throws Throwable
*/
@Override
public Object intercept(Invocation invocation) throws Throwable {
System.out.println("DownloadPlugin............Before");
final Object proceed = invocation.proceed();//调用原方法
System.out.println("DownloadPlugin............After");
return proceed;
}
}
@Intercepts({
@Signature(type = Download.class, method = "download", args = {String.class}),
@Signature(type = Parser.class, method = "parse", args = {String.class})
})
public class GlobalPlugin implements Interceptor {
/**
* 这个方法会直接覆盖原有方法
* @param invocation
* @return
* @throws Throwable
*/
@Override
public Object intercept(Invocation invocation) throws Throwable {
System.out.println("GlobalPlugin............Before");
final Object proceed = invocation.proceed();//调用原方法
System.out.println("GlobalPlugin............After");
return proceed;
}
}
@Intercepts({@Signature(type = Parser.class,method = "parse",args = {String.class})})
public class ParserPlugin implements Interceptor {
/**
* 这个方法会直接覆盖原有方法
* @param invocation
* @return
* @throws Throwable
*/
@Override
public Object intercept(Invocation invocation) throws Throwable {
System.out.println("ParserPlugin............Before");
final Object proceed = invocation.proceed();//调用原方法
System.out.println("ParserPlugin............After");
return proceed;
}
}
测试主类
public class PluginTest {
public static void main(String[] args) {
InterceptorChain interceptorChain = new InterceptorChain();
interceptorChain.addInterceptor(new DownloadPlugin());
interceptorChain.addInterceptor(new ParserPlugin());
interceptorChain.addInterceptor(new GlobalPlugin());
Download downloadProxy = (Download) interceptorChain.pluginAll(new SimpleDownload());
Parser parserProxy = (Parser) interceptorChain.pluginAll(new SimpleParser());
String response = downloadProxy.download("aaaaaa");
Map<String, String> parse = parserProxy.parse(response);
System.out.println(parse.toString());
}
}
输出结果:
GlobalPlugin............Before
DownloadPlugin............Before
执行了下载
DownloadPlugin............After
GlobalPlugin............After
GlobalPlugin............Before
ParserPlugin............Before
执行解析
ParserPlugin............After
GlobalPlugin............After
{value=dddddddddddddddddddddddddd, key=dddddddddddddddddddddddddd}
欢迎把你的测试结果打在评论区