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"/>
            <property name="password" value="123456"/>
        </plugin>
    </plugins>

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

MyFirstPlugin.java

package com.gong.mybatis.dao;

import java.util.Properties;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import 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创建的动态代理
        return wrap;
    }

    //将插件注册时的property属性设置进来
    @Override
    public void setProperties(Properties properties) {
        // TODO Auto-generated method stub
        System.out.println("插件配置的信息:"+properties);
    }

}

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

package com.gong.mybatis.test;

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

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.junit.Test;

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

public class TestMybatis5 {

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

    @Test
    public void test() throws IOException {
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        SqlSession openSession = sqlSessionFactory.openSession();

        try {
            EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
            Employee em = mapper.getEmpById(1);
            System.out.println(em);
        } finally {
            // TODO: handle finally clause
            openSession.close();
        }
    }

}

输出:

插件配置的信息:{password=123456, username=root}
-->myfirstplugin...plugin,将要包装的对象:[email protected]
-->myfirstplugin...plugin,将要包装的对象:[email protected]3da5
-->myfirstplugin...plugin,将要包装的对象:[email protected]4973
-->myfirstplugin...plugin,将要包装的对象:[email protected]65367
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, gender=1, email[email protected], dept=null]

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

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

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

MySecondPlugin.java

package com.gong.mybatis.dao;

import java.util.Properties;

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

@Intercepts(
        {
            @Signature(type=StatementHandler.class,method="parameterize",args=java.sql.Statement.class)
        })
public class MySecondPlugin implements Interceptor{

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("MySecondPlugin...intercept:"+invocation.getMethod());
        return invocation.proceed();
    }

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

    @Override
    public void setProperties(Properties properties) {
        // TODO Auto-generated method stub
    }

}

结果:

插件配置的信息:{password=123456, username=root}
-->myfirstplugin...plugin,将要包装的对象:[email protected]
MySecondPlugin...plugin,要包装的对象:[email protected]
-->myfirstplugin...plugin,将要包装的对象:[email protected]3da5
MySecondPlugin...plugin,要包装的对象:[email protected]3da5
-->myfirstplugin...plugin,将要包装的对象:[email protected]4973
MySecondPlugin...plugin,要包装的对象:[email protected]4973
-->myfirstplugin...plugin,将要包装的对象:[email protected]65367
MySecondPlugin...plugin,要包装的对象:[email protected]65367
DEBUG 01-23 13:21:17,640 ==>  Preparing: select id,last_name lastName,email,gender from tbl_employee where id = ?   (BaseJdbcLogger.java:145)
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 <==      Total: 1  (BaseJdbcLogger.java:145)
Employee [id=1, lastName=dema, gender=1, email[email protected], dept=null]

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

原文地址:https://www.cnblogs.com/xiximayou/p/12230518.html

时间: 2024-08-08 05:29:05

mybatis插件开发初探的相关文章

Android插件开发初探——基础篇

Android插件开发初探 对于Android的插件化其实已经讨论已久了,但是市面上还没有非常靠谱成熟的插件框架供我们使用.这里我们就尝试性的对比一下Java中,我们使用插件化该是一个怎么样的流程,且我们如何将此流程移植到Android框架上去使用.很多代码都是内部资料,不喜勿喷,谢谢~ 为什么要插件化? 功能越来越多 代码.安装包越来越大 小的更新也需要重新发布 更新频繁,安装成本太大 用户无法选择性加载需要的模块 -- 插件化的好处 主安装包较小 强制模块化,降低耦合度 减少整体更新的次数

Android插件开发初探——分析篇

承接上文 Android插件开发初探--基础篇 http://blog.csdn.net/yzzst/article/details/45582315 我们通过使用DexClassLoader能够将classes.dex中的类动态的加载进入当前进程.当然,也就可以预先定一些代理的接口完成四大组件的功能. 整体功能如下图所示: 当然,对于一个Android的应用程序而言,只是动态的加载类与声明四大组件是不够的.如下图所示,使我们常见到的一个APK文件解压缩后的文件内容. 有过Android项目开发

深入理解Mybatis插件开发

背景 关于Mybatis插件,大部分人都知道,也都使用过,但很多时候,我们仅仅是停留在表面上,知道Mybatis插件可以在DAO层进行拦截,如打印执行的SQL语句日志,做一些权限控制,分页等功能:但对其内部实现机制,涉及的软件设计模式,编程思想往往没有深入的理解. 本篇案例将帮助读者对Mybatis插件的使用场景,实现机制,以及其中涉及的编程思想进行一个小结,希望对以后的编程开发工作有所帮助. 注:本案例以mybatis 3.4.7-SNAPSHOT版本为例. PS:文章是挺久之前写的,当时花了

mybatis插件开发

1. 插件初始化 MyBATIS是在初始化上下文环境的时候就初始化插件的,我们看到源码: 它最后是把所有的插件按你配置的顺序保存在一个list对象里面. 3.插件的取出: MyBATIS的插件可以拦截Executor,StatementHandler,ParameterHandler和ResultHandler对象(下简称四大对象)

MyBatis结果映射与MyBatis缓存初探学习记录

MyBatis高级结果映射(一对一.一对多.多对多的映射),延迟加载,查询缓存(一级缓存),二级缓存的学习记录: 1.学习中所使用到的例子,数据库基础分析 2.高级结果映射 3.延迟加载 4.一级缓存 5.二级缓存 1.学习中所使用到的例子,数据库基础分析 2.高级结果映射 resultType与resultMap: resultType来进行结果映射,数据库中查询几条记录,那么在resultType就会映射成几条记录:resultType映射是一个平铺式的映射: resultMap比较繁琐一些

ssm之spring+springmvc+mybatis整合初探

1.基本目录如下  2.首先是向lib中加入相应的jar包  3.然后在web.xml中加入配置,使spring和springmvc配置文件起作用. <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/

【Mybtais】Mybatis 插件 Plugin开发(一)动态代理步步解析

需求: 对原有系统中的方法进行'拦截',在方法执行的前后添加新的处理逻辑. 分析: 不是办法的办法就是,对原有的每个方法进行修改,添加上新的逻辑:如果需要拦截的方法比较少,选择此方法到是会节省成本.但是面对成百上千的方法怎么办?此时需要用到动态代理来实现. 场景: 例如:对原有的系统添加日志记录.添加性能分析等等... 举例: 如下,需要对Sleep对象的sleep方法进行"拦截",并在此方法的执行前后添加新的逻辑.想知道'睡觉前干了什么?睡觉后干了什么?' interface Sle

初探MyBatis之HelloWorld(三)

三.用SQL映射语句用注解,dataSource用xml(不推荐). 综合上面两节(一个用xml,一个用annotation),发现一个好玩儿的,SQL映射用注解方式,然后还是得有两个xml配置文件. 如果你不知道SQL映射怎么用注解方式,查看这篇:http://www.cnblogs.com/hyyq/p/6718449.html 当SQL语句用注解方式映射后,原来的XML映射文件可以这样写: 这是原来用xml映射SQL语句的方式(这里的mapper节点的 namespace和select节点

MyBatis实现与插件开发

分析源码之前也需要源码下载并安装到本地仓库和开发工具中,方便给代码添加注释:安装过程和mybatis源码的安装过程是一样的,这里就不再重复描述了:下载地址:https://github.com/mybatis/spring 1.SqlSessionFactoryBean源码分析 2.MapperFactoryBean源码分析 3.MapperScannerConfigurer源码分析 插件开发原理 插件是用来改变或者扩展mybatis的原有的功能,mybaits的插件就是通过继承Intercep