66. }catch(NoSuchMethodExceptione){
67. thrownewPluginException("Couldnotfindmethodon"+sig.ty
pe()+"named"+sig.method()+".Cause:"+e,e);
68. }
69. }
70. returnsignatureMap;
71. }
72.
73. privatestaticClass<?>[]getAllInterfaces(Class<?>type,Map<Class<
?>,Set<Method>>signatureMap){
74. Set<Class<?>>interfaces=newHashSet<Class<?>>();
75. while(type!=null){
76. for(Class<?>c:type.getInterfaces()){
77. if(signatureMap.containsKey(c)){
78. interfaces.add(c);
79. }
80. }
81. type=type.getSuperclass();
82. }
83. returninterfaces.toArray(newClass<?>[interfaces.size()]);
84. }
85.
86. }
我们先看一下 Plugin 的 wrap 方法,它根据当前的 Interceptor 上面的注解定义哪些接
口需要拦截,然后判断当前目标对象是否有实现对应需要拦截的接口,如果没有则返回目
标对象本身,如果有则返回一个代理对象。而这个代理对象的 InvocationHandler 正是一个
Plugin。所以当目标对象在执行接口方法时,如果是通过代理对象执行的,则会调用对应
InvocationHandler 的 invoke 方法,也就是 Plugin 的 invoke 方法。所以接着我们来看一下
该 invoke 方法的内容。这里 invoke 方法的逻辑是:如果当前执行的方法是定义好的需要
拦截的方法,则把目标对象、要执行的方法以及方法参数封装成一个 Invocation 对象,再
把封装好的 Invocation 作为参数传递给当前拦截器的 intercept 方法。如果不需要拦截,则
直接调用当前的方法。Invocation 中定义了定义了一个 proceed 方法,其逻辑就是调用当
前方法,所以如果在 intercept 中需要继续调用当前方法的话可以调用 invocation 的
procced 方法。
这就是 Mybatis 中实现 Interceptor 拦截的一个思想,如果用户觉得这个思想有问题或
者不能完全满足你的要求的话可以通过实现自己的 Plugin 来决定什么时候需要代理什么时
候需要拦截。以下讲解的内容都是基于 Mybatis 的默认实现即通过 Plugin 来管理
Interceptor 来讲解的。
对于实现自己的 Interceptor 而言有两个很重要的注解,一个是@Intercepts,其值是一
个@Signature 数组。@Intercepts 用于表明当前的对象是一个 Interceptor,而@Signature
则表明要拦截的接口、方法以及对应的参数类型。来看一个自定义的简单 Interceptor:
Java 代码}}