深入浅出Mybatis(三)Mybatis配置插件,自定义插件

722 阅读3分钟

Mybatis插件介绍

Mybatis作为优秀的开源框架,本身具有非常强大的灵活性,在四大组件Executor,StatementHandler,ParamterHandler,ResultSetHandler处提供了简单易用的插件扩展机制。Mybatis对持久层的操作就借助于这四大组件,并且支持插件对四大组件进行拦截,插件的本质就是拦截器,用来增强功能,增强功能本质上是通过动态代理实现,换句话说,Mybatis的四大对象都是代理对象。

四大组件的结构图:

在这里插入图片描述

Mybatis所有允许拦截的方法如下:

  • 执行器Executor (update、query、commit、rollback等方法);
  • SQL语法构建器StatementHandler (prepare、parameterize、batch、updates query等方 法);
  • 参数处理器ParameterHandler (getParameterObject、setParameters方法);
  • 结果集处理器ResultSetHandler(handleResultSets、handleOutputParameters等方法);

插件执行原理

MyBatis在启动时可以加载插件,并保存插件实例到相关对象(InterceptorChain,拦截器链) 中。待准备工作做完后,MyBatis处于就绪状态。我们在执行SQL时,需要先通过DefaultSqlSessionFactory创建SqlSessionExecutor实例会在创建 SqlSession 的过程中被创建,Executor实例创建完毕后,MyBatis会通过JDK动态代理为实例生成代理类。这样,插件逻辑即可在Executor相关方法被调用前执行。

自定义拦截器

自定义拦截器核心就是我们自定义一个类实现Interceptor接口,并实现里边的关键方法:

  • Intercept方法,插件的核心方法
  • plugin方法,生成target的代理对象
  • setProperties方法,传递插件所需参数

1.在之前项目的基础上定义MyPlugin.java

@Intercepts({
        //注意看这个大花括号,也就这说这里可以定义多个@Signature对多个地方拦截,都用这个拦截器
        @Signature(type = StatementHandler.class,method = "prepare", args = {Connection.class, Integer.class})
})
public class MyPlugin implements Interceptor {
    /**
     *  拦截方法:只要被拦截得目标对象的目标方法被执行时,该方法就会执行
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("自定义逻辑,对方法进行了增强");
        return invocation.proceed();
    }

    /**
     * 将当前的拦截器生成代理对象存到拦截器链中
     */
    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    /**
     * 获取配置文件参数
     */
    @Override
    public void setProperties(Properties properties) {
        System.out.println("获取到的配置文件的参数是:"+properties);
    }
}

这里主要介绍@Signature的三个属性

  • type:指拦截哪个接口
  • method: 指拦截哪个具体的方法
  • args:声明该方法的参数,必须按接口定义的顺序写,主要为了在有方法重载的情况下精确定位到我们要拦截的方法
  1. sqlMapConfig.xml中注册我们自定义的插件:
<plugins>
    <plugin interceptor="com.lagou.plugin.MyPlugin">
        <!-- 设置参数,这里随便定义的  -->
        <property name="name" value="tom"/>
    </plugin>
</plugins>

这里我们自定义的插件只是简单的在控制台打印了一句话,并没有做什么具体的逻辑,只是为了演示效果,接下来我们随便运行一个查询方法,查看结果:

首先是插件初始化阶段,控制台先打印了我们定义的参数: 在这里插入图片描述

然后我们拦截的是查询方法,所以我们具体的增强逻辑是在我们只想查询动作之前进行的:

在这里插入图片描述

可以看出我们的增强逻辑是在执行sql语句之前执行的。

常用插件介绍

pageHelper分页插件

分页助手PageHelper是将分页的复杂操作进行封装,使用简单的方式即可获得分页的相关数据,极大的简化开发。

  1. 首先在pom.xml中添加依赖
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>3.7.5</version>
</dependency>
<dependency>
    <groupId>com.github.jsqlparser</groupId>
    <artifactId>jsqlparser</artifactId>
    <version>0.9.1</version>
</dependency>
  1. mybatis核心配置文件sqlMapConfig.xml中注册PageHelper插件
<plugins>
    <plugin interceptor="com.github.pagehelper.PageHelper">
        <property name="dialect" value="mysql"/>
    </plugin>
</plugins>
  1. 具体使用方法,新建PageHelperTest.java测试类
public class PageHelperTest {
    private UserMapper userMapper;

    @Before
    public void before() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        userMapper = sqlSession.getMapper(UserMapper.class);
    }

    @Test
    public void pageHelperTest() throws IOException {
        //设置分页参数
        PageHelper.startPage(2, 3);
        List<User> userList = userMapper.findAll();
        for (User user : userList) {
            System.out.println(user);
        }
        PageInfo<User> userPageInfo = new PageInfo<User>(userList);
        System.out.println("总条数:"+userPageInfo.getTotal());
        System.out.println("总页数:"+userPageInfo.getPages());
        System.out.println("当前页:"+userPageInfo.getPageNum());
        System.out.println("每页展示条数:"+userPageInfo.getPageSize());
    }
}

关键代码 PageHelper.startPage(2, 3);必须放在我们的查询语句之前。

测试结果:

在这里插入图片描述

说明

文章内容输出来源:拉勾教育Java高薪训练营课程归纳总结