服务器之家

服务器之家 > 正文

mybatis中的扩展实现源码解析

时间:2021-06-27 15:11     来源/作者:此生重演

前言

最近项目中需要用到mybatis扩展,就深入看了下mybatis的实现,对其灵活性和扩展性的设计思想还是非常佩服的

首先说一下mybatis的拦截器使用方法:继承其intercepter接口,实现org.apache.ibatis.plugin.interceptor#intercept方法,在其中或者对其要执行的方法进行拦截,或者对返回值进行解析

同时基于org.apache.ibatis.plugin.interceptsorg.apache.ibatis.plugin.signature这两个注解来决定,对哪些执行器的哪些方法进行拦截

先看下拦截器的核心接口

?
1
2
3
4
5
6
7
8
9
public interface interceptor {
 
 object intercept(invocation invocation) throws throwable;
 
 object plugin(object target);
 
 void setproperties(properties properties);
 
}

其中intercept方法是核心方法,拦截器的实现,plugin方法是用于配置哪些对哪些执行器进行拦截

继续看源码,可以看到mybatis的拦截是使用了jdk的动态代理实现的,本质上是一种代理机制

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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;
 }
 
 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;
 }
 
 @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 exceptionutil.unwrapthrowable(e);
 }
 }
 
 ......
}

mybatis的这个plugin就是代理类,这个代理类是在org.apache.ibatis.plugin.interceptor#plugin方法中初始化的(调用org.apache.ibatis.plugin.plugin#wrap),一个plugin包含一个intercepter,以及该intercepter相关的注解配置信息,当对拦截对象的对应方法进行执行的时候,都会根据这些注解配置来判断是否需要执行该代理拦截(org.apache.ibatis.plugin.plugin#invoke

再看下plugin是如何被加载的:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class interceptorchain {
 
 private final list<interceptor> interceptors = new arraylist<interceptor>();
 
 public object pluginall(object target) {
 for (interceptor interceptor : interceptors) {
  target = interceptor.plugin(target);
 }
 return target;
 }
 
 public void addinterceptor(interceptor interceptor) {
 interceptors.add(interceptor);
 }
 
 public list<interceptor> getinterceptors() {
 return collections.unmodifiablelist(interceptors);
 }
 
}

org.apache.ibatis.plugin.interceptor#plugin是在org.apache.ibatis.plugin.interceptorchain#pluginall方法中调用的,我们可以看到,如果一个应用中注册了多个拦截器,那么实际上是会进行一个for循环的加载,由于上面说到了,加载一次,本质上是对mybatis的执行期进行一次代理包装,那么加载多次的话,就会代理包装多次,实际上就是一种多重代理了,这样就保证了每次调用都会按照代理顺序进行调用和返回的处理

可以看到,在做这些mybatis执行器初始化的时候,都会进行拦截器链的加载

mybatis中的扩展实现源码解析

至此,mybatis基于jdk动态代理的扩展实现方法就了解清楚了,其灵活性在于,它抽象了执行器的概念,并且拦截器的拦截方法也是固定的,我们可以对不同执行器的不同方法进行拦截,而对这些扩展点进行扩展却不用写多个方法实现多个方法,只需要实现一个接口就可以搞定了!

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对服务器之家的支持。

原文链接:http://www.cnblogs.com/cishengchongyan/p/10208040.html

标签:

相关文章

热门资讯

2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全
2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全 2019-12-26
yue是什么意思 网络流行语yue了是什么梗
yue是什么意思 网络流行语yue了是什么梗 2020-10-11
背刺什么意思 网络词语背刺是什么梗
背刺什么意思 网络词语背刺是什么梗 2020-05-22
苹果12mini价格表官网报价 iPhone12mini全版本价格汇总
苹果12mini价格表官网报价 iPhone12mini全版本价格汇总 2020-11-13
2021德云社封箱演出完整版 2021年德云社封箱演出在线看
2021德云社封箱演出完整版 2021年德云社封箱演出在线看 2021-03-15
返回顶部