MyBatis学习-7

MyBatis插件

Posted by lvyonghao on April 20, 2019

MyBatis学习-7

经过源码的讲解,我们都对四大对象有了了解,当我们四大对象在创建的时候。

  • 每个创建的对象不是直接返回的,而是调用PluginAll
  • 获取到所有的Interceptor(拦截器)就是插件需要实现的接口,调用interceptor.Plugin(target),返回target包装后的对象
  • 插件机制,我们可以使用插件为目标对象创建一个代理对象,AOP(面向切面)

1.编写Interceptor接口的实现类

现在Dao包下写一个新的类,MyFirstPlugin,继承接口

package com.snake_lvyonghao.MyBatis.Dao;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.*;

import java.sql.Statement;
import java.util.Properties;

public class MyFirstPlugin implements Interceptor {


    /**
     * intercept拦截:
     *          拦截目标对象的目标方法的执行
     * @param invocation
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {

        System.out.println("MyFirstPlugin...intercept:" + invocation.getMethod());

        //执行目标方法
        Object proceed = invocation.proceed();

        //返回执行后的返回值
        return proceed;
    }

    /**
     * 插件包装
     *      为目标对象创建一个代理对象
     * @param o
     * @return
     */
    @Override
    public Object plugin(Object o) {
        //借助Plugin的weap方法来使用当前Interceptor对象
        System.out.println("MyFirstPlugin.... Plugin" + o);
        Object wrap = Plugin.wrap(o,this);

        //返回当前traget创建的动态代理
        return wrap;
   }


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

具体内容我都放在注释当中,一共三个方法,intercept的拦截,插件的包装,已经注册插件时的proprerty属性设置进来。


2.使用@Intercepts注解完成插件签名

使用两个注解设置拦截的类型,方法,拦截的参数表。

 * 插件的签名,告诉MyBatis当前插件拿来拦截那个方法
 */
@Intercepts({
      @Signature(type = StatementHandler.class,method = "parameterize",args = java.sql.Statement.class)
})

3.将写好的插件注册的全局配置文件

    <plugins>
        <plugin interceptor="com.snake_lvyonghao.MyBatis.Dao.MyFirstPlugin">
            <property name="username" value="root"/>
            <property name="password" value="12345678"/>
        </plugin>
    </plugins>

注意的的就是能在<property name="" value=""/>当中添加一些配置信息。


4.多个插件

和单个插件插件的流程一样,创建一个实现Interceptor接口,加上注释,写入配置文件。需要注意的是,多个插件会产生多层代理,层层代理意味着在执行目标方法的时候我们会先执行最外层的代理方法,也就是最后一个插件,以此类推。


5.简单的插件开发

我们可以在类中的intercept方法当中去去实现插件的开发,比如我们原本查询id=1的信息,现在改为查询4的信息就可以这样做

package com.snake_lvyonghao.MyBatis.Dao;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;

import java.sql.Statement;
import java.util.Properties;


/**
 * 插件的签名,告诉MyBatis当前插件拿来拦截那个方法
 */
@Intercepts({
      @Signature(type = StatementHandler.class,method = "parameterize",args = java.sql.Statement.class)
})
public class MyFirstPlugin implements Interceptor {


    /**
     * intercept拦截:
     *          拦截目标对象的目标方法的执行
     * @param invocation
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {

        System.out.println("MyFirstPlugin...intercept:" + invocation.getMethod());

        //动态的改变一下sql运行的参数
        Object target = invocation.getTarget();
        System.out.println("拦截的方法" + invocation.getTarget());

        //拿到StatmentHandler==》ParameterHandler==》parameterObject
        MetaObject metaObject = SystemMetaObject.forObject(target);
        Object value = metaObject.getValue("parameterHandler.parameterObject");
        System.out.println("sql参数是" + value);
        metaObject.setValue("parameterHandler.parameterObject",4);

        //执行目标方法
        Object proceed = invocation.proceed();

        //返回执行后的返回值
        return proceed;
    }

    /**
     * 插件包装
     *      为目标对象创建一个代理对象
     * @param o
     * @return
     */
    @Override
    public Object plugin(Object o) {
        //借助Plugin的weap方法来使用当前Interceptor对象
        System.out.println("MyFirstPlugin.... Plugin" + o);
        Object wrap = Plugin.wrap(o,this);

        //返回当前traget创建的动态代理
        return wrap;
    }


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

当然让我们自己写插件还有点远,先熟悉一下流程吧

6.PageHelper插件进行分页

这是一个第三方的分页插件,我们先来学一下怎么用这个插件,首先百度PageHelper,在github上找到这个项目,查看他的文档,你可以选择下载jar包,或者通过Maven来引入插件,再根据你的情况可以在MyBatis的配置文件中配置拦截器插件,或者在Spring配置文件中配置拦截器插件 Maven <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>最新版本</version> </dependency> MyBatis

<!-- 
    plugins在配置文件中的位置必须符合要求,否则会报错,顺序如下:
    properties?, settings?, 
    typeAliases?, typeHandlers?, 
    objectFactory?,objectWrapperFactory?, 
    plugins?, 
    environments?, databaseIdProvider?, mappers?
-->
<plugins>
    <!-- com.github.pagehelper为PageHelper类所在包名 -->
    <plugin interceptor="com.github.pagehelper.PageInterceptor">
        <!-- 使用下面的方式配置参数,后面会有所有的参数介绍 -->
        <property name="param1" value="value1"/>
	</plugin>
</plugins>

Spring

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  <!-- 注意其他配置 -->
  <property name="plugins">
    <array>
      <bean class="com.github.pagehelper.PageInterceptor">
        <property name="properties">
          <!--使用下面的方式配置参数,一行配置一个 -->
          <value>
            params=value1
          </value>
        </property>
      </bean>
    </array>
  </property>
</bean>

剩下的相关设置去看文档就好了,里面介绍的很详细了。