dubbo源码深度解析_mybatis 3.x源码深度解析与最佳实践(5)

42d948d0d1741e9076dd869de31c4697.png

Mybatis的插件实现原理(JDK动态代理+责任链模式

HelloService //目标接口
    sayHello() //目标方法
  
HelloServiceImpl //目标接口实现类
​
Invocation //是目标方法的封装
  public Object process() throws Exception{
       return method.invoke(target,args);
    }
​
Interceptor //拦截器接口
    intercept(Invocation invocation); //拦截方法,执行拦截器逻辑
    public Object plugin(Object target) {
        return TargetProxy.wrap(target,this);
    } //创建代理对象并返回
​
InterceptorChain //拦截器链类
    private List<Interceptor> interceptorList = new ArrayList<>();
    public Object pluginAll(Object target) {
        for (Interceptor interceptor : interceptorList) {
            target = interceptor.plugin(target);//插入拦截器
        }
        return target;
    }
​

主要说明拦截器接口,包括两个重要方法,一个是intercept里面是拦截器的主要逻辑,还有一个是plugin方法,用来创建目标方法和拦截器的代理类。

subInvocationHandler implenents InvocationHandler //自定义代理对象需要实现代理接口
    invoke(Object proxy, Method method, Object[] args){
        Invocation invocation = new Invocation(target,method,args);
        return interceptor.intercept(invocation);
    }//代理类执行目标会回调invoke
​    
//代理类的创建
public static Object wrap(Object target,Interceptor interceptor) {
        SubInvocationHandler targetProxy = new SubInvocationHandler(target, interceptor);
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                                      target.getClass().getInterfaces(),targetProxy);
    }

代理类执行时,会回调InvocationHandler的invoke。在invoke中会调用拦截器的intercept方法。

//测试方法
public class Test {
    public static void main(String[] args) {
        HelloService target = new HelloServiceImpl();
        Interceptor transactionInterceptor = new TransactionInterceptor();
        LogInterceptor logInterceptor = new LogInterceptor();
        InterceptorChain interceptorChain = new InterceptorChain();
        interceptorChain.addInterceptor(transactionInterceptor);
        interceptorChain.addInterceptor(logInterceptor);
        target = (Target) interceptorChain.pluginAll(target);
        target.sayHello();
    }
}

创建目标对象和拦截器,将拦截器添加到拦截器链。调用拦截器链的pluginAll嵌套创建代理对象(调用拦截器的plugin方法)。target.sayHello()方法执行时会回调自定义代理类InvocationHandler的invoke方法,再invoke中会调用interceptor的intercept(invocation)方法,在最后一个拦截器中会执行invocation.process()调用目标方法。

mybatis Plugin

Plugin类实现了InvocationHandler接口;

调用ParameterHandler,ResultSetHandler,StatementHandler,Executor时会执行Plugininvoke方法,并根据@Intercepts的配置信息(方法名,参数等)动态判断是否需要拦截该方法.再然后使用需要拦截的方法Method封装成Invocation,并调用Interceptor的proceed方法。

拦截器代理类对象->拦截器->目标方法
Executor.Method->Plugin.invoke->Interceptor.intercept->Invocation.proceed->method.invoke

Interceptor接口 :org.apacheibatis.plugin.Interceptor

public interface Interceptor {
  //当plugin函数返回代理,就可以对其中的方法进行拦截来调用intercept方法
  Object intercept(Invocation invocation) throws Throwable;
  //plugin方法是拦截器用于封装目标对象的,通过该方法我们可以返回目标对象本身,也可以返回一个它的代理。
  Object plugin(Object target);
 //在Mybatis配置文件中指定一些属性
  void setProperties(Properties properties);
}

拦截器上注解接口配置

@Intercepts({@Signature( type= Executor.class,  method = "update", 
                        args ={MappedStatement.class,Object.class})})
  • type:表示拦截的类,这里是Executor的实现类
  • method:表示拦截的方法,这里是拦截Executor的query方法
  • args:表示方法参数

这个拦截器会拦截Executor接口的update方法

mybatis的拦截器链的入口

在Configuration实例化Executor、ParameterHandler、ResultSetHandler、StatementHandler四大接口对象的时候调用interceptorChain.pluginAll()方法插入进去的。其实就是循环执行拦截器链所有的拦截器的plugin() 方法,mybatis官方推荐的plugin方法是Plugin.wrap() 方法,这个类就是我们上面的TargetProxy类。

  1. Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed) MyBatis的执行器,用于执行增删改查操作;
  2. ParameterHandler (getParameterObject, setParameters) 处理SQL的参数对象;
  3. .ResultSetHandler (handleResultSets, handleOutputParameters) 处理SQL的返回结果集;
  4. StatementHandler (prepare, parameterize, batch, update, query) 拦截Sql语法构建的处理;

bab8967f9e3c587a4c825da8aa5b7901.png

参考地址:https://www.cnblogs.com/qdhxhz/p/11390778.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值