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类生成代理对象足够我们使用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值