好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

mybatis中的扩展实现源码解析

前言

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

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

同时基于 org.apache.ibatis.plugin.intercepts 和 org.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基于jdk动态代理的扩展实现方法就了解清楚了,其灵活性在于,它抽象了执行器的概念,并且拦截器的拦截方法也是固定的,我们可以对不同执行器的不同方法进行拦截,而对这些扩展点进行扩展却不用写多个方法实现多个方法,只需要实现一个接口就可以搞定了!

总结

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

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

查看更多关于mybatis中的扩展实现源码解析的详细内容...

  阅读:9次