原生Mybitas的Interceptor和Plugin

借鉴了读写分离框架,大概了解了实现原理,顺手写了这篇博客

  • Mybitas的Dao层实际上是一个代理对象,在执行的时候先走MapperProxy.invoke()

主要代码

pom.xml

   <dependencies>
        <!-- 添加log4j -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.16</version>
        </dependency>

        <!-- 添加mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.2.6</version>
        </dependency>

        <!-- 添加mysql驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.12</version>
        </dependency>

    </dependencies>

mybitas.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <!-- 指定Mybatis使用log4j -->
    <settings>
        <setting name="logImpl" value="LOG4J"/>
    </settings>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <!--
                如果上面没有指定数据库配置的properties文件,那么此处可以这样直接配置
               -->
              <property name="driver" value="com.mysql.jdbc.Driver"/>
              <property name="url" value="jdbc:mysql://localhost:3306/test1"/>
              <property name="username" value="root"/>
              <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

    <!-- 映射文件,mybatis精髓, 后面才会细讲 -->
    <mappers>
        <mapper resource="com/dao/userDao-mapping.xml"/>
    </mappers>

</configuration>

Main

package com;

import com.dao.UserDao;
import com.entity.User;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.*;

import java.io.IOException;
import java.util.Properties;

/**
 * @author :liujipeng
 * @date :Created in 2019/12/27 14:58
 * @description:${description}
 */
public class Application {
    public static void main(String[] args) {
        SqlSession sqlSession = getSessionFactory().openSession();
        UserDao userMapper = sqlSession.getMapper(UserDao.class);
        User user = userMapper.findUserById(1);
    }

    private static SqlSessionFactory getSessionFactory() {
        SqlSessionFactory sessionFactory = null;
        String resource = "mybitas.xml";
        try {
            sessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader(resource));
        } catch (IOException e) {
            e.printStackTrace();
        }
        MyInterceptor myInterceptor = new MyInterceptor();
        sessionFactory.getConfiguration().addInterceptor(myInterceptor);
        return sessionFactory;
    }
//拦截器
    @Intercepts({ @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class,
            RowBounds.class, ResultHandler.class}),
            @Signature(type = Executor.class, method = "update", args = {MappedStatement.class,
                    Object.class})})
    static class MyInterceptor implements Interceptor {
        public Object intercept(Invocation invocation) throws Throwable {
            return invocation.proceed();
        }
        public Object plugin(Object target) {
            return Plugin.wrap(target, this);
        }
        public void setProperties(Properties properties) {
        }
    }

}

userDao-mapping.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.dao.UserDao">

    <select id="findUserById" resultType="com.entity.User" >
        select * from user where id = #{id}
    </select>
    <update id="updateUser" >
        update user set name = "sds" where id = #{id}
    </update>

</mapper>

关于Mapper.xml 文件的加载和"select|insert|update|delete"的解析此次先不进行说明,全部被解析后封存在Configuration.mappedStatements<String, MappedStatement> key就是namespace+id形式储存的

Interceptor和Plugin

我的application里面在SqlSessionFactory初始化完成的时候会将自己写的 MyInterceptor添加到 InterceptorChain 里面。
在这里插入图片描述

在什么时候进行调用呢

在获得SqlSessionFactory后就要获取SqlSession,此时就会发生第一次拦截

在这里插入图片描述
根据openSession()方法进来,我们会看到如下得到一个执行器
在这里插入图片描述
在打开获取执行器的方法里面我们可以看到获取了所有的拦截器
在这里插入图片描述
在这里插入图片描述
这个interceptor.plugin(target)就进入了自己设置的interceptor里面
在这里插入图片描述
这个Plugin.wrap方法继续跟进去
在这里插入图片描述
signatureMap获取的是自己在Interceptor的注解上定义的内容,key 就是type值对象,value存的是Executor.class里面通过nethid和args得到的方法
在这里插入图片描述
target是newExecutor里面传进去的,有此处可见是CachingExecutor对象
在这里插入图片描述
因此interfaces里面会得到一个CachingExecutor数组对象,如下
在这里插入图片描述
回头再看这个三元运算符,则会返回Plugin针对CachingExecutor的代理对象。
在这里插入图片描述
然后的方法就是一路返回,直到返回SqlSession在这里插入图片描述
上面这一步返回的是 MapperProxy的代理对象,在执行xxxMapper.find()方法的时候会走如下
在这里插入图片描述
![在这里插入图片描述](https://img-blog.csdnimg.cn/20191228133944939.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3h1eGllMTM=,size_16,color_FFFFFF,t_70
在这里插入图片描述
然后就会走到上面这个地方,这个 executor就是上面Plugin产生的代理对象,当执行的时候会先走 Plugin.invoke()
在这里插入图片描述
method.getDeclaringClass() 得到的是进入Plugin的这个方法的方法对象,在wrap()的时候已经初始化了signatureMap数据,此次是大于0的,因此就又走了
this.interceptor.intercept(new Invocation(this.target, method, args)) 这个就是自定义的intercept方法中
在这里插入图片描述
至此,mybitas的Interceptor就结束了,后面的就是mybitas 自己的初始化各种链接查询了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值