mybatis插件开发初探

运行流程:

/**
 * 1、获取sqlSessionFactory对象:
 *         解析文件的每一个信息保存在Configuration中,返回包含Configuration的DefaultSqlSession;
 *         注意:【MappedStatement】:代表一个增删改查的详细信息
 * 
 * 2、获取sqlSession对象
 *         返回一个DefaultSQlSession对象,包含Executor和Configuration;
 *         这一步会创建Executor对象;
 * 
 * 3、获取接口的代理对象(MapperProxy)
 *         getMapper,使用MapperProxyFactory创建一个MapperProxy的代理对象
 *         代理对象里面包含了,DefaultSqlSession(Executor)
 * 4、执行增删改查方法
 * 
 * 总结:
 *     1、根据配置文件(全局,sql映射)初始化出Configuration对象
 *     2、创建一个DefaultSqlSession对象,
 *         他里面包含Configuration以及
 *         Executor(根据全局配置文件中的defaultExecutorType创建出对应的Executor)
 *  3、DefaultSqlSession.getMapper():拿到Mapper接口对应的MapperProxy;
 *  4、MapperProxy里面有(DefaultSqlSession);
 *  5、执行增删改查方法:
 *          1)、调用DefaultSqlSession的增删改查(Executor);
 *          2)、会创建一个StatementHandler对象。
 *              (同时也会创建出ParameterHandler和ResultSetHandler)
 *          3)、调用StatementHandler预编译参数以及设置参数值;
 *              使用ParameterHandler来给sql设置参数
 *          4)、调用StatementHandler的增删改查方法;
 *          5)、ResultSetHandler封装结果
 *  注意:
 *      四大对象每个创建的时候都有一个interceptorChain.pluginAll(parameterHandler);
 */

 首先要在mybatis全局配置文件中配置:

    <!--plugins:注册插件  -->
    <plugins>
        plugin interceptor="com.gong.mybatis.dao.MyFirstPlugin">
            property name="username" value="root"/>
            ="password"="123456"/>
        </plugin>
    >

property为自定义的属性名和值。

MyFirstPlugin.java

package com.gong.mybatis.dao;

import java.util.Properties;

 org.apache.ibatis.executor.statement.StatementHandler;
 org.apache.ibatis.plugin.Interceptor;
 org.apache.ibatis.plugin.Intercepts;
 org.apache.ibatis.plugin.Invocation;
 org.apache.ibatis.plugin.Plugin;
 org.apache.ibatis.plugin.Signature;


//完成插件签名,用于拦截哪个对象的哪个方法

@Intercepts({
    @Signature(type=StatementHandler.class,method="parameterize",args=java.sql.Statement.class)
})
public class MyFirstPlugin implements Interceptor {
    
     * intercept:拦截
     * */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
         TODO Auto-generated method stub
        System.out.println("myfirstplugin...intercept:"+invocation.getMethod());
        执行目标方法
        Object proceed = invocation.proceed();
        返回执行后的返回值
        return proceed;
    }
    
    包装目标对象,为目标对象创建一个代理对象
    @Override
    public Object plugin(Object target) {
        System.out.println("-->myfirstplugin...plugin,将要包装的对象:"+target);
         TODO Auto-generated method stub
        Object wrap = Plugin.wrap(target,this);
        返回为当前target创建的动态代理
         wrap;
    }
    
    将插件注册时的property属性设置进来
void setProperties(Properties properties) {
         TODO Auto-generated method stub
        System.out.println("插件配置的信息:"+properties);
    }

}

我们进行测试:随便运行一个要测试的方法

 com.gong.mybatis.test;

 java.io.IOException;
 java.io.InputStream;
 java.util.ArrayList;
 java.util.Arrays;
 java.util.HashMap;
 java.util.List;
 java.util.Map;

 org.apache.ibatis.io.Resources;
 org.apache.ibatis.session.SqlSession;
 org.apache.ibatis.session.SqlSessionFactory;
 org.apache.ibatis.session.SqlSessionFactoryBuilder;
 org.junit.Test;

 com.gong.mybatis.bean.Department;
 com.gong.mybatis.bean.Employee;
 com.gong.mybatis.dao.EmployeeMapper;
 com.gong.mybatis.mapper.EmployeeMapperDynamicSql;

 TestMybatis5 {
    
    public SqlSessionFactory getSqlSessionFactory()  IOException {
        String resource = "mybatis-config.xml";
        InputStream is = Resources.getResourceAsStream(resource);
        return new SqlSessionFactoryBuilder().build(is);
    }

    @Test
    void test()  IOException {
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        SqlSession openSession = sqlSessionFactory.openSession();
        
        try {
            EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.);
            Employee em = mapper.getEmpById(1);
            System.out.println(em);
        } finally {
             TODO: handle finally clause
            openSession.close();
        }
    }
    
}

输出:

插件配置的信息:{password=123456,username=root}
-->myfirstplugin...plugin,将要包装的对象:org.apache.ibatis.executor.CachingExecutor@23faf8f2
-->myfirstplugin...plugin,将要包装的对象:org.apache.ibatis.scripting.defaults.DefaultParameterHandler@1563da5
-->myfirstplugin...plugin,将要包装的对象:org.apache.ibatis.executor.resultset.DefaultResultSetHandler@34c4973
-->myfirstplugin...plugin,将要包装的对象:org.apache.ibatis.executor.statement.RoutingStatementHandler@7a765367
DEBUG 01-23 12:59:28,739 ==>  Preparing: select id,last_name lastName,email,gender from tbl_employee where id = ?   (BaseJdbcLogger.java:145) 
myfirstplugin...intercept:public abstract void org.apache.ibatis.executor.statement.StatementHandler.parameterize(java.sql.Statement) throws java.sql.SQLException
DEBUG 01-23 12:59:28,823 ==> Parameters: 1(Integer)  (BaseJdbcLogger.java:145) 
DEBUG 01-23 12:59:28,850 ==      Total: 1  (BaseJdbcLogger.java:145) 
Employee [id=1,lastName=dema,1)">genderemail=dema@qq.com,1)">dept=null]

说明:执行sql方法时会调用四大对象,如果不是自己配置拦截的类型,就放过,否则就进行拦截。我们定义的插件是拦截StatementHandler类中的parameterize方法,其参数为java.sql.Statement。

当有多个插件时是怎么运行的?

    ="com.atguigu.mybatis.dao.MyFirstPlugin"="com.atguigu.mybatis.dao.MySecondPlugin"></>

MySecondPlugin.java

 org.apache.ibatis.plugin.Signature;

@Intercepts(
        {
            @Signature(type=StatementHandler.)
        })
class MySecondPlugin  Interceptor{

    @Override
     Throwable {
        System.out.println("MySecondPlugin...intercept:"+ invocation.proceed();
    }

    @Override
     Object plugin(Object target) {
         TODO Auto-generated method stub
        System.out.println("MySecondPlugin...plugin,要包装的对象:"+return Plugin.wrap(target,1)">);
    }

    @Override
     TODO Auto-generated method stub
    }

}

结果:

MySecondPlugin...intercept:public abstract void org.apache.ibatis.executor.statement.StatementHandler.parameterize(java.sql.Statement) throws java.sql.SQLException
myfirstplugin...intercept:public abstract void org.apache.ibatis.executor.statement.StatementHandler.parameterize(java.sql.Statement) throws java.sql.SQLException
DEBUG 01-23 13:21:17,698 ==> Parameters: 1(Integer)  (BaseJdbcLogger.java:145) 
DEBUG 01-23 13:21:17,731 =null]

需要注意一点:插件会按配置的顺序依次拦截,但在执行时会先执行后配置的,因为相当于为第一个代理对象再进行代理。

相关文章

1.pom.xml引入依赖 &lt;dependency&gt; &lt;gro...
&lt;?xml version=&quot;1.0&quot; encoding=&a...
准备工作 ① 创建数据库&amp;数据表 ## 创建数据库 CREA...
MyBatis逆向工程是指根据数据库表结构自动生成对应的实体类、...
MyBatis获取参数值的两种方式:${}和#{} ${}的本质就是字符串...
resultMap作用是处理数据表中字段与java实体类中属性的映射关...