SpringBoot集成MyBatis自定义插件

Mybatis核心对象介绍

MyBatis的主要的核心部件有以下几个:

  1. Configuration 初始化基础配置,比如MyBatis的别名等,一些重要的类型对象,如,插件,映射器,ObjectFactory和typeHandler对象,MyBatis所有的配置信息都维持在Configuration对象之中
  2. SqlSessionFactory SqlSession工厂
    SqlSession 作为MyBatis工作的主要顶层API,表示和数据库交互的会话,完成必要数据库增删改查功能
  3. Executor MyBatis执行器,是MyBatis 调度的核心,负责SQL语句的生成和查询缓存的维护
  4. StatementHandler 封装了JDBC Statement操作,负责对JDBC statement 的操作,如设置参数、将Statement结果集转换成List集合。
    ParameterHandler 负责对用户传递的参数转换成JDBC Statement 所需要的参数,
  5. ResultSetHandler 负责将JDBC返回的ResultSet结果集对象转换成List类型的集合;
  6. TypeHandler 负责java数据类型和jdbc数据类型之间的映射和转换
  7. MappedStatement MappedStatement维护了一条节点的封装,
  8. SqlSource 负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回
  9. BoundSql 表示动态生成的SQL语句以及相应的参数信息

Mybatis执行图

SpringBoot集成MyBatis自定义插件_第1张图片

MyBatis 拦截器步骤流程

  1. Mybatis支持对Executor、StatementHandler、PameterHandler和ResultSetHandler 接口进行拦截,也就是说会对这4种对象进行代理
  2. 主要有两种不同的形式构建configuration并添加拦截器interceptor
    第一种:通过SqlSessionFactoryBean去构建Configuration添加拦截器并构建获取SqlSessionFactory。
    第二种:通过原始的XMLConfigBuilder 构建configuration添加拦截器,这里主要是解析配置文件的plugin节点,根据配置的interceptor 属性实例化Interceptor 对象,然后添加到Configuration 对象中的InterceptorChain 属性中。
  3. 定义了拦截器链,初始化配置文件的时候就把所有的拦截器添加到拦截器链中,mybatis 在实例化Executor、ParameterHandler、ResultSetHandler、StatementHandler四大接口对象的时候调用interceptorChain.pluginAll() 方法插入进去的。其实就是循环执行拦截器链所有的拦截器的plugin() 方法,mybatis官方推荐的plugin方法是Plugin.wrap() 方法,这个类就TargetProxy类。

自定义拦截器步骤和解析

拦截对象 拦截对象作用 拦截方法
Executor 拦截执行器的方法 update, query, flushStatements, commit, rollback,getTransaction, close, isClosed
ParameterHandler 拦截参数的处理 getParameterObject, setParameters
ResultHandler 拦截结果集的处理 prepare, parameterize, batch, update, query
StatementHandler 拦截Sql语法构建的处理 handleResultSets, handleOutputParameters

拦截器类注解:

@Intercepts({@Signature(
    type = '' ,
    method = "",
    args = {}
)})

@Intercepts:标识该类是一个拦截器;
@Signature:指明自定义拦截器需要拦截哪一个类型,哪一个方法;

  1. type:上述四种类型中的一种;
  2. method:对应接口中的哪类方法(因为可能存在重载方法);
  3. args:对应哪一个方法的入参;

Intercepts注解需要一个Signature(拦截点)参数数组。通过Signature来指定拦截哪个对象里面的哪个方法。@Intercepts注解定义如下:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Intercepts {
    /**
     * 定义拦截点
     * 只有符合拦截点的条件才会进入到拦截器
     */
    Signature[] value();
}

Signature来指定咱们需要拦截那个类对象的哪个方法。定义如下:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({})
public @interface Signature {
  /**
   * 定义拦截的类 Executor、ParameterHandler、StatementHandler、ResultSetHandler当中的一个
   */
  Class type();

  /**
   * 在定义拦截类的基础之上,在定义拦截的方法
   */
  String method();

  /**
   * 在定义拦截方法的基础之上在定义拦截的方法对应的参数,
   * JAVA里面方法可能重载,故注意参数的类型和顺序
   */
  Class[] args();
}

标识拦截注解@Intercepts规则使用,简单实例如下:


@Intercepts({//注意看这个大花括号,也就这说这里可以定义多个@Signature对多个地方拦截,都用这个拦截器
        @Signature(
                type = ResultSetHandler.class,
                method = "handleResultSets", 
                args = {Statement.class}),
        @Signature(type = Executor.class,
                method = "query",
                args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})


下面开始实现自定义拦截器
1.自定义注解类实现org.apache.ibatis.plugin.Interceptor接口,重写以下方法:`public class MybatisPageIntercepter implements Interceptor {

@Override
public Object intercept(Invocation invocation) throws Throwable {
    return null;
}

@Override
public Object plugin(Object o) {
    return null;
}

@Override
public void setProperties(Properties properties) {

}

}`

2.添加拦截器注解@Intercepts{…}。具体值遵循上述规则设置。

@Intercepts({@Signature(type = Executor.class,method = "update",args = {MappedStatement.class,Object.class}),
        @Signature(type = Executor.class,method = "query",args = {MappedStatement.class,Object.class, RowBounds.class, ResultHandler.class})})

3.配置文件中添加拦截器。

#扫描mybatis-config.xml
mybatis.config-location=classpath:mybatis/mybatis-config.xml

SpringBoot集成MyBatis自定义插件_第2张图片

intercept(Invocation invocation)

入参invocation便是指拦截到的拦截的四种类型对象。
举例说明:拦截**StatementHandler#query(Statement st,ResultHandler rh)**方法,那么Invocation就是该对象。

plugin(Object target)

这个方法的作用是就是让mybatis判断,是否要进行拦截,然后做出决定是否生成一个代理。

  @Override
    public Object plugin(Object target) {
    //判断是否拦截这个类型对象(根据@Intercepts注解决定),然后决定是返回一个代理对象还是返回原对象。
//故我们在实现plugin方法时,要判断一下目标类型,如果是插件要拦截的对象时才执行Plugin.wrap方法,否则的话,直接返回目标本身。
        if (target instanceof StatementHandler) {
            return Plugin.wrap(target, this);
        }
        return target;
    }

ps:每经过一个拦截器对象都会调用插件的plugin方法,也就是说,该方法会调用4次。根据@Intercepts注解来决定是否进行拦截处理。

setProperties(Properties properties)

拦截器需要一些变量对象,而且这个对象是支持可配置的。

拦截器通过实现Mybatis提供的Interceptor拦截接口,重写了三个方法:setProperties/plugin/ intercept,三者执行顺序是setProperties—》plugin—》Interceptor。

     setProperties方法:该方法通过设置属性,将核心配置文件configuration.xml文件中对拦截器的配置项下的属性获取过来,便于在拦截器中使用。

     plugin方法:该方法用来协商,达成协议,把代理权给普通的业务员this,传进wrap方法实现的源码去做代理,没有获取代理权的代理人在这个地方就会停下,不会向下走了,获取代理权的代理人可以去做拦截代理。

    intercept方法:则是获取拦截对象下的要拦截的东西,然后对其加以改编,添加自己的行为,按照条件进行改编拦截对象,然后通过源码下的反射invocation来调用被拦截的方法,让原本被拦截的方法继续执行(invocation.proceed())。

你可能感兴趣的:(spring,boot,java,spring)