原生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 自己的初始化各種鏈接查詢了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章