[MyBatis学习笔记] 四、Mybatis插件

7 篇文章 0 订阅

一、Mybatis插件简介

Mybatis的四大组件ExecutorStatementHandlerParameterHandlerResultSetHandler均提供了插件扩展机制,供开发者对组件功能进行扩展。Mybatis支持用插件对上述四大核心对象进行拦截,以增强核心对象的功能,其本质上是借助动态代理实现的。

默认情况下,MyBatis 允许使用插件来拦截的方法调用包括1

Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
ParameterHandler (getParameterObject, setParameters)
ResultSetHandler (handleResultSets, handleOutputParameters)
StatementHandler (prepare, parameterize, batch, update, query)

二、Mybatis插件原理

四大核心对象在创建时,创建的对象并不会直接返回,而是通过InterceptorChain#pluginAll(Object target)方法进行了处理,在该方法中,又会调用每个拦截器(自定义插件)的plugin方法(Interceptor#plugin(Object target))对该target对象进行逐一增强处理。

三、简单的源码分析

自定义插件的相关属性可在mybatis-config.xml文件中配置:
在这里插入图片描述
插件类ExamplePlugin如下:
在这里插入图片描述
由于plugins标签在mybatis-config.xml中配置,因此本文会以XMLConfigBuilder.java作为入口来进行分析。

1、起点: XMLConfigBuilder

起步顺序为:XMLConfigBuilder#parse() -> XMLConfigBuilder#parseConfiguration(XNode) -> XMLConfigBuilder#pluginElement(XNode),这里以pluginElement方法作为开始:

XMLConfigBuilder#pluginElement:
在这里插入图片描述

2、Configuration

Configuration#addInterceptor:
在这里插入图片描述

可见,创建出的拦截器对象放入了Configuration类的interceptorChain属性中。
进入InterceptorChainaddInterceptor方法:
InterceptorChain#addInterceptor
在这里插入图片描述
再次回到Configuration类中,查看interceptorChain属性的使用情况:
Configuration# newParameterHandler(MappedStatement, Object, BoundSql):
在这里插入图片描述
Configuration#newResultSetHandler():
在这里插入图片描述
Configuration#newStatementHandler():
在这里插入图片描述
Configuration#newExecutor:
在这里插入图片描述
上述四个方法中,并未直接返回创建好的相应对象,而是首先调用了InterceptorChain中的pluginAll方法,再将其返回值作为最终返回值。

3、InterceptorChain

那么,在InterceptorChain#pluginAll(Object)中,发生了什么呢:
InterceptorChain#pluginAll:
在这里插入图片描述

4、Interceptor

Interceptor#plugin:
在这里插入图片描述

使用jdk动态代理创建对象:
Plugin#wrap:
在这里插入图片描述
Plugin类实现了InvocationHandler接口,其invoke方法如下:
在这里插入图片描述
最后,可以在Invocation类中的proceed方法执行之前或之后,来执行相关的增强逻辑:
在这里插入图片描述

四、简单示例

1、DemoPlugin

@Intercepts({
        @Signature(
                type = StatementHandler.class,
                method = "prepare",
                args = {Connection.class, Integer.class}
        )
})
public class DemoPlugin implements Interceptor {

    /**
     * 拦截方法:只要被拦截的目标对象的目标方法被执行时,都会执行intercept方法
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
		System.out.println("对方法进行了增强, 开始...");
        Object proceed = invocation.proceed();
        System.out.println("对方法进行了增强, 结束!");
        return proceed;
    }

    /**
     * 主要为了把当前的拦截器生成代理存到拦截器链中
     */
    @Override
    public Object plugin(Object target) {
        System.out.println("生成了代理对象");
        return Plugin.wrap(target, this);
    }

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

2、mybatis-config.xml

<plugins>
        <plugin interceptor="com.gavin11.study.mybatis.plugin.DemoPlugin" >
            <property name="name" value="gavin"/>
            <property name="gender" value="male"/>
        </plugin>
    </plugins>

3、测试程序

public class Test {

    public static void main(String[] args) throws Exception {
        SqlSessionFactory sqlSessionFactory;
        try (
                InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
                InputStreamReader isr = new InputStreamReader(Objects.requireNonNull(in), StandardCharsets.UTF_8)
        ) {
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(isr);
        }

        try (
                SqlSession session = sqlSessionFactory.openSession()
        ) {
            UserMapper userMapper = session.getMapper(UserMapper.class);

            User user1 = userMapper.findByIdNameAnn(new User(1, "lucy", null, null));
            System.out.println(user1);
        }
    }
}

4、运行结果

获取到的配置文件参数是: {name=gavin, gender=male}
生成了代理对象
生成了代理对象
生成了代理对象
生成了代理对象
对方法进行了增强, 开始...
对方法进行了增强, 结束!
User{id=1, username='lucy', password='123', birthday='2019-12-12', orders=null, roles=null}

参考:


  1. Mybatis插件简介↩︎

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值