1. 简介
一般情况下,开源框架会提供插件或者其它形式的扩展点,供开发者自行扩展。这样可以增加框架的灵活性,开发者可以结合实际需求,对框架进行扩展。Mybatis可以基于插件实现分页、分表、监控等功能。由于插件与业务无关,业务也无法感知插件的存在。因此可以无感植入插件,在无形中增强功能。
2. Mybatis插件介绍
- Mybatis支持插件对四大核心对象进行拦截
- Executor:执行器,update、query、commit、rollback等方法。
- StatementHandler:sql语法构建器,prepare、parameterize、batch、update、query等方法。
- ParameterHandler:参数处理器,getParameterObject、setParameterObject等方法。
- ResultSetHandler:结构集处理器,handleResultsets、handleOutputParameters等方法。
3. Mybatis插件原理
总结:使用jdk动态代理为四大对象创建代理对象
在四大对象创建的时候:
- 每个对象创建出来不是直接返回的,而是通过interceptorChain(parameterHandler)方法进行处理。
- 获取到所有的Interceptor(拦截器)(插件需要实现的接口),调用interceptor.plugin(target),返回target包装后的对象
- 插件机制,我们可以使用插件为目标创建一个代理对象,AOP我们的插件可以为四大对象创建出代理对象,代理对象就可以拦截到四大对象的每一个执行
- 以ParameterHandler为例看插件是如何进行代理的: ```java public ParameterHandler newParameterHandler(MappedStatement mappedStatement,Object object,BoundSql,boundSql,InterceptorChain interceptorChain) { ParameterHandler parameterHandler = mappedStatement.getLang.createParameterHandler(mappedStatement,object,sql); parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler); return parameterHandler; }
public Object pluginAll(Object target) { for(Interceptor interceptor : interceptors) { target = interceptor.plugin(target); } return target; }
5. interceptorChain保存了所有的拦截器(interceptors),是mybatis初始化的时候创建的。interceptor.plugin(target)中的target可以理解为mybatis的四大对象,返回的是被重重代理后的对象。6. 自定义插件,比如拦截Executor中的query方法:1. 定义一个类,实现Interceptor接口```java@Interceptors({@Signature(type = Executor.class,method = "query",args = {MappedStatement.class,Object.class,RowBounds.class,ResultHandler.class})})public class ExamplePlugin implements Interceptor {//省略逻辑}
- 将插件配置到sqlMapperConfig中
<plugins><plugin interceptor = "com.test.plugin.ExamplePlugin"></plugin></plugins>
4. 自定义Mybatis插件
创建一个类
@Intercepts({@Signature(// 拦截哪个类type = StatementHandler.class,// 拦截哪个方法method = "prepare",// 方法的参数,如果有方法重载就看参数args = {Connection.class,Integer.class})})public class MyPlugin implements Interceptor {/*** 拦截方法:只要目标对象的目标方法被执行时,每次都会执行intercept方法* @param invocation* @return* @throws Throwable*/@Overridepublic Object intercept(Invocation invocation) throws Throwable {System.out.println("对方法进行了增强...");// 让原方法执行return invocation.proceed();}/*** 主要为了把当前的拦截器生成代理存到拦截链中* @param target* @return*/@Overridepublic Object plugin(Object target) {// this表示当前类(也就是自定义的拦截器)return Plugin.wrap(target,this);}/*** 获取配置文件的参数* @param properties*/@Overridepublic void setProperties(Properties properties) {}}
配置文件sqlMapConfig.xml
<plugins><plugin interceptor="com.lagou.plugin.MyPlugin"/></plugins>
