Mybatis源码学习第七天(插件源码分析)

时间:2022-07-26
本文章向大家介绍Mybatis源码学习第七天(插件源码分析),主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

为了不把开发和源码分析混淆,决定分开写;

接下来分析一下插件的源码,说道这里老套路先说一个设计模式,他就是责任链模式

责任链模式:就是把一件工作分别经过链上的各个节点,让这些节点依次处理这个工作,和装饰器模式不同,每个节点都知道后继者是谁,适合为完成同一个请求需要多个处理类的场景;

Handler:定义了一个处理请求的标准接口;

ConcreteHandler:具体的处理者,处理他负责的部分,根据业务可以结束处理流程,也可以将请求转发给他的后继者;

client:发送者,发起请求的客户端;

责任链模式优点:

1:降低耦合度,他将请求的发送者和接受者解耦;

2:简化了对象,使得对象不需要知道链的结构;

3:增强给对象指派责任的灵活性,通过改变链内的成员或者调动他们的次序,允许动态的新增或者删除责任;

4:增加新的请求处理类很方便;

Mybatis插件模块源码分析

1:插件的初始化(XMLConfigBuilder.pluginElement);

2:插件的加载(Configuration.new*方法,四大对象的创建);

3:插件的调用(Plugin.wrap,Plugin.invoke);

Mybatis插件理解

1 pluginElement(root.evalNode("plugins"));//从这行代码开始解析插件节点

 1 /**
 2    * 解析所有的插件节点
 3    * @param parent
 4    * @throws Exception
 5    */
 6   private void pluginElement(XNode parent) throws Exception {
 7     if (parent != null) {
 8       // 遍历所有的插件配置
 9       for (XNode child : parent.getChildren()) {
10         // 获取插件的类名
11         String interceptor = child.getStringAttribute("interceptor");
12         // 获取插件的配置
13         Properties properties = child.getChildrenAsProperties();
14         // 实例化插件对象
15         Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).getDeclaredConstructor().newInstance();
16         // 设置插件的属性 所以在插件中才可以得到XML中配置的属性
17         interceptorInstance.setProperties(properties);
18         // 将插件添加到configuration中 底层采用list保存所有的插件并记录顺序
19         // InterceptorChain 存在的类
20         // private final List<Interceptor> interceptors = new ArrayList<>();
21         configuration.addInterceptor(interceptorInstance);
22       }
23     }
24   }

其实在这里也不是经典的责任链模式,就像tomcat的filter一样,他并不知道自己的下一个节点是谁,他的顺序是由配置决定的由上而下的;其实这样演变也是有好处的就是解开了下级节点和当前节点的耦合,完全由配置决定;

 1 public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
 2     executorType = executorType == null ? defaultExecutorType : executorType;
 3     executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
 4     Executor executor;
 5     if (ExecutorType.BATCH == executorType) {
 6       executor = new BatchExecutor(this, transaction);
 7     } else if (ExecutorType.REUSE == executorType) {
 8       executor = new ReuseExecutor(this, transaction);
 9     } else {
10       executor = new SimpleExecutor(this, transaction);
11     }
12     // 如果存在<cache>节点 那么通过装饰器CachingExecutor 包装原始的executor
13     if (cacheEnabled) {
14       executor = new CachingExecutor(executor);
15     }
16     // 通过InterceptorChain遍历所有的插件为Executor增强,添加插件的功能
17     executor = (Executor) interceptorChain.pluginAll(executor);
18     return executor;
19   }
1 public Object pluginAll(Object target) {
2     for (Interceptor interceptor : interceptors) {
3       // 这里调用的就是实现interceptor接口实现的plugin方法 传入目标对象
4       target = interceptor.plugin(target);
5     }
6     return target;
7   }

接下来看一下实现类中的plugin方法,在接口中可以定义默认方法实现之后我们的实现类中已经不需要重写plugin方法 了我们看一下接口中的

1 /**
2    *
3    * @param target 被拦截的对象,他的作用就是给拦截的对象生成一个代理对象
4    * @return
5    */
6   default Object plugin(Object target) {
7     return Plugin.wrap(target, this);
8   }
 1 /**
 2    * 静态方法,用于帮助Interceptor生成动态代理
 3    * @param target
 4    * @param interceptor
 5    * @return
 6    */
 7   public static Object wrap(Object target, Interceptor interceptor) {
 8     // 解析Interceptor上标志的@Intercepts注解得到的Signature信息
 9     Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
10     // 获取目标对象的类型
11     Class<?> type = target.getClass();
12     // 获取目标对象实现的接口,拦截器可以拦截4大对象实现的接口
13     Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
14     if (interfaces.length > 0) {
15       // 使用JDK动态代理
16       return Proxy.newProxyInstance(
17           type.getClassLoader(),
18           interfaces,
19           new Plugin(target, interceptor, signatureMap));
20     }
21     return target;
22   }

至于Plugin.invoke就是调用的我们实现的Interceptor接口的intercept方法;

作者:彼岸舞

时间:2020324

内容关于:Mybatis

本文部分来源于网络,只做技术分享,一概不负任何责任