您当前的位置: 首页 >  mybatis

white camel

暂无认证

  • 0浏览

    0关注

    442博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

MyBatis插件开发 : 插件原理、插件开发流程

white camel 发布时间:2021-04-22 16:53:32 ,浏览量:0

在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 增强代码 在这里插入图片描述

MyBatis在四大对象的创建过程中,都会有插件进行介入。插件可以利用动态代理机制一层层的包装目标对象,而实现在目标对象执行目标方法之前进行拦截的效果。MyBatis 允许在已映射语句执行过程中的某一点进行拦截调用。 默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:

  • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  • ParameterHandler (getParameterObject, setParameters)
  • ResultSetHandler (handleResultSets, handleOutputParameters)
  • StatementHandler (prepare, parameterize, batch, update, query) 在这里插入图片描述
/**
 * 插件原理
 * 在四大对象创建的时候
 * 1、每个创建出来的对象不是直接返回的,而是
 * 		interceptorChain.pluginAll(parameterHandler);
 * 2、获取到所有的Interceptor(拦截器)(插件需要实现的接口);
 * 		调用interceptor.plugin(target);返回target包装后的对象
 * 3、插件机制,我们可以使用插件为目标对象创建一个代理对象;AOP(面向切面)
 * 		我们的插件可以为四大对象创建出代理对象;
 * 		代理对象就可以拦截到四大对象的每一个执行;
 */ 
public Object pluginAll(Object target) {
    for (Interceptor interceptor : interceptors) {
      target = interceptor.plugin(target);
    }
    return target;
}
1、编写插件
/**
 * Description:
 *
 * @author guizy
 * @date 2021/4/22 12:58
 */
@SuppressWarnings("all")
/*
    完成插件签名: 告诉MyBatis当前插件用来拦截哪个对象哪个方法
 */
@Intercepts(
        {
                @Signature(type = StatementHandler.class, method = "parameterize", args = java.sql.Statement.class)
        }
)
public class MyPlugin implements Interceptor {

    /**
     * 拦截对象目标方法的执行
     *
     * @param invocation 拦截
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("MyPlugin.intercept:" + invocation.getMethod());
        // 执行目标方法
        Object proceed = invocation.proceed();
        return proceed;
    }

    /**
     * 包装目标对象, 包装: 为目标对象创建一个代理对象
     *
     * @param target
     * @return
     */
    @Override
    public Object plugin(Object target) {
        System.out.println("MyPlugin.plugin mybatis将要包装的对象" + target);
        // 该方法就是让当前的Interceptor拦截器来包装我们的对象
        Object wrap = Plugin.wrap(target, this);
        // wrap就是target的动态代理对象
        return wrap;
    }

    /**
     * 将插件注册时的property属性设置进来
     *
     * @param properties
     */
    @Override
    public void setProperties(Properties properties) {
        System.out.println("插件配置的信息: " + properties);
    }
}
2、配置插件

    
        
            
            
            
        
    
3、测试插件

随便执行一个查询方法, 因为拦截的是StatementHandler的parameterize的方法, 因为在mapper.getUser的时候, 底层会调用这个预编译参数方法, 所以会拦截到该方法

@Test
public void testQueryOneUser(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();

    // 使用方式一: 来找到SQL并执行
    //User user = sqlSession.selectOne("com.sunny.dao.UserMapper.getUser", 1L);

    // 使用方式二: 来找到SQL并执行
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    // 实际上底层调用的还是sqlSession的方法,注意:sqlSession调用CRUD方法只能传递一个参数
    User user = mapper.getUser(12);

    System.out.println(user);
    sqlSession.close();
}

在这里插入图片描述

打印信息

// 打印了配置的信息
插件配置的信息: {password=8888, username=root}
// 这里在创建4大对象的时候, 都会调用PluginAll方法, 然后里面会拿到所有实现Interceptor的
// 拦截器进行拦截包装
MyPlugin.plugin mybatis将要包装的对象org.apache.ibatis.executor.CachingExecutor@77ec78b9
MyPlugin.plugin mybatis将要包装的对象org.apache.ibatis.scripting.defaults.DefaultParameterHandler@42607a4f
MyPlugin.plugin mybatis将要包装的对象org.apache.ibatis.executor.resultset.DefaultResultSetHandler@25bbf683
MyPlugin.plugin mybatis将要包装的对象org.apache.ibatis.executor.statement.RoutingStatementHandler@7276c8cd
DEBUG [main] - ==>  Preparing: SELECT * FROM user WHERE id = ?; 
// 只会为StatementHandler对象创建代理对象, 拦截到parameterize方法
// 因为Executor, parameterHandler, ResultSetHandler的签名不属于StatementHandler
// 所以就没有为它们创建代理对象
MyPlugin.intercept:public abstract void org.apache.ibatis.executor.statement.StatementHandler.parameterize(java.sql.Statement) throws java.sql.SQLException
DEBUG [main] - ==> Parameters: 12(Integer)
TRACE [main] -   Preparing: SELECT * FROM user WHERE id = ?; 
MyPlugin.intercept:public abstract void org.apache.ibatis.executor.statement.StatementHandler.parameterize(java.sql.Statement) throws java.sql.SQLException
当前拦截到的对象: org.apache.ibatis.executor.statement.RoutingStatementHandler@7276c8cd
sql语句传入的参数为:1
DEBUG [main] - ==> Parameters: 2(Integer)
TRACE [main] -             
关注
打赏
1661428283
查看更多评论
0.0921s