SSM-Mybatis-插件-插件的代理和反射设计

SSM-Mybatis-插件-插件的代理和反射设计

插件用的是责任链模式,而Mybatis的责任链模式是通过interceptorChain

executor=(Executor) interceptorChain.pluginAll(executor);

pluginAll方法代码:

    public Object pluginAll(Object target) {
    
    
        Interceptor interceptor;
        for(Iterator var2 = this.interceptors.iterator(); var2.hasNext(); target = interceptor.plugin(target)) {
    
    
            interceptor = (Interceptor)var2.next();
        }

        return target;
    }

plugin方法是生成代理对象的方法,从Configuration对象中取出插件的

​ 自己编写代理类工作量很大,Mybatis提供一个常用工具类,用来生成代理对象,它是Plugin,这个类实现了InvocationHandler接口,采用JDK动态代理,该类有两个重要方法:

public class Plugin implements InvocationHandler {
    
    
    
    ...
    
        public static Object wrap(Object target, Interceptor interceptor) {
    
    
            Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
            Class<?> type = target.getClass();
            Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
            return interfaces.length > 0 ? Proxy.newProxyInstance(type.getClassLoader(), interfaces, new Plugin(target, interceptor, signatureMap)) : target;
    }
    
    
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
            try {
    
    
                Set<Method> methods = (Set)this.signatureMap.get(method.getDeclaringClass());
                return methods != null && methods.contains(method) ? this.interceptor.intercept(new Invocation(this.target, method, args)) : method.invoke(this.target, args);
            } catch (Exception var5) {
    
    
                throw ExceptionUtil.unwrapThrowable(var5);
            }
    }
    
    ...
    
}

wrap:方法生成这个对象的动态代理对象

invoke:使用这个类为插件生成代理对象,那么代理对象在调用方法时就会进入invoke方法中。在invoke方法中,如果存在签名的拦截方法,插件的intercept方法就会在这里调用,然后返回结果。如果不存在签名方法,那么将直接反射调度要执行的方法

Mybatis把被代理对象,反射方法及参数,都传递给了Invocation类的结构方法,用以生成一个Invocation类对象,Invocation类中有一个proceed()方法,

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 this.target;
   }

   public Method getMethod() {
    
    
       return this.method;
   }

   public Object[] getArgs() {
    
    
       return this.args;
   }

   public Object proceed() throws InvocationTargetException, IllegalAccessException {
    
    
       return this.method.invoke(this.target, this.args);
   }
}

从源码看到,proceed方法通过反射的方法调度被代理对象的真实方法。

大部分情况下,Mybatis的Plugin类生成代理对象足够我们使用

猜你喜欢

转载自blog.csdn.net/weixin_43958223/article/details/114537897