Mybatis实现自定义Plugins拦截器

场景

MyBatis 自定义拦截器,可以拦截的接口只有四种 Executor.class,StatementHandler.class,ParameterHandler.class 和 ResultSetHandler.class。
在某种情景下,如果这四种接口自带的某个方法不能满足我们的要求时,如 Executor主要是创建Statement对象,在创建过程中依靠 MappedStatement 对象将赋值内容给 sql 占位符进行绑定,在Mybatis 中主要有4种实现:BatchExecutor、ReuseExecutor、SimpleExecutor 和 CachingExecutor。如果你觉得这4种实现Executor 接口的 query 方法都不能满足你的要求,那么可以在不改动源码的情况下,建立一个自己的拦截器用于拦截 Executor 接口的 query 方法。
我们可以选择在这些被拦截的方法执行前后加上自己的一些逻辑,也可以选择不执行被拦截的方法,只执行自己的一些逻辑
定义自己的拦截器可以通过实现Mybatis提供的Interceptor接口来实现:
QueryInterceptor.java

package com.lks.plugin;

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.util.Properties;

/**
 * Created by likaisong on 2019/2/25.
 */
@Intercepts(
        @Signature(method = "query" ,
        type = Executor.class,
                args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
)
public class QueryInterceptor implements Interceptor {
    /**
     * 拦截时执行的操作
     *
     * @param invocation { 代理对象,被监控方法对象,当前被监控方法运行时需要的实参 }
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("被拦截方法执行前的操作。。。");
        Object proceed = invocation.proceed();
        System.out.println("被拦截方法执行后的操作。。。");
        return proceed;
    }

    /**
     * 拦截器用于封装目标对象的
     * 通过该方法我们可以返回目标对象本身,也可以返回一个它的代理
     *
     * @param o
     * @return
     */
    @Override
    public Object plugin(Object o) {
        return Plugin.wrap(o, this);
    }

    /**
     * 用于在 Mybatis 配置文件中指定一些属性的。
     *
     * @param properties
     */
    @Override
    public void setProperties(Properties properties) {

    }
}

主要实现 plugin 方法和 intercept 方法:
plugin 方法主要是返回拦截的对象,其中Plugin类中有个静态方法 wrap(Object target,Interceptor interceptor),通过该方法可以决定要返回的对象是目标对象还是对应的代理。
intercept 方法主要是进行拦截的时候要执行的方法,也就是在此处实现自己的一些操作。
另外,要想MyBatis框架识别出你自定义的拦截器,需要通过注解的方式表明,一个是 @Intercepts,其值是一个@Signature 数组。@Intercepts 用于表明当前的对象是一个 Interceptor,而 @Signature则表明要拦截的接口、方法以及对应的参数类型。
Signature里的参数不清楚的,可以打开你要拦截的方法的源码,如本例子中的query方法:

<E> List<E> query(MappedStatement var1, Object var2, RowBounds var3, ResultHandler var4) throws SQLException;

在 MyBatis 配置文件中注册自定义拦截器
mybatis-config.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>
    <typeHandlers>
        <typeHandler handler="com.lks.handler.DateToStringTypeHandler" javaType="java.util.Date" jdbcType = "VARCHAR"/>
    </typeHandlers>
    <plugins>
        <plugin interceptor="com.lks.plugin.QueryInterceptor"></plugin>
    </plugins>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis_demo"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="userMapper.xml"/>
    </mappers>
</configuration>

主要看plugin节点
userMapper.xml文件中添加测试语句
userMapper.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,namespace的值习惯上设置成包名+sql映射文件名,这样就能够保证namespace的值是唯一的-->
<mapper namespace="userMapper">
    <!--自定义拦截器-->
    <select id="queryInterceptor" parameterType="int"
            resultType="com.lks.domain.User" >
        select * from users where id=#{id}
    </select>
</mapper>

测试类中添加测试代码:
TestMain.java

package com.lks.test;

import com.lks.domain.User;
import com.lks.mapper.UserMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.testng.annotations.AfterTest;
import org.testng.annotations.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.Date;

/**
 * Created by likaisong on 2019/2/24.
 */
public class TestMain {
    private static SqlSession session;

    private static SqlSession getSqlSession(String resource) {
        if (resource == null || "".equals(resource)) {
            return null;
        }
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
        } catch (IOException e) {
            e.printStackTrace();
        }
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        session = sqlSessionFactory.openSession();
        return session;
    }
    @Test
    public static void testQueryIntercepor() {
        String resource = "mybatis-config.xml";
        session = getSqlSession(resource);
        String statement = "userMapper.queryInterceptor";
        User user = session.selectOne(statement, 1);
        System.out.println(user);
    }
    @AfterTest
    public static void closeSession() {
        session.close();
    }
}

执行完毕后就可以在控制台中看到打印的语句了,可以根据业务需要,添加自己的逻辑。

猜你喜欢

转载自blog.csdn.net/lks1139230294/article/details/87927756