Mybatis的plugin

xiaoxiao2025-04-29  15

plugin的配置

本来想直接写Mybatis插件PageHelper的,但里面涉及了mybatis的plugin,所以就顺便了解下Mybatis的plugin。通常我们使用 Mybatis插件时,都会使用下面的配置。配置如下:

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <plugins> <plugin interceptor="org.mybatis.example.ExamplePlugin"> <property name="someProperty" value="100"/> </plugin> </plugins> </configuration>

Mybatis的插件配置会存储在Configuration内部,初始化时,会读取这些插件,保存于Configuration对象的InterceptorChain中。Configuration的InterceptorChain定义如下:

public class Configuration { protected final InterceptorChain interceptorChain = new InterceptorChain(); }

2.如何编写一个插件

首先需要实现org.apache.ibatis.plugin.Interceptor接口。Interceptor接口定义如下: 

下面编写一个插件,代码如下:

@Intercepts({@Signature( type= Executor.class, method = "update", args = {MappedStatement.class,Object.class})}) //要拦截Executor接口内的update()方法,参数类型为args列表 public class ExamplePlugin implements Interceptor { public Object intercept(Invocation invocation) throws Throwable { return invocation.proceed(); } // 用于给target创建一个JDK的动态代理对象,触发intercept()方法 public Object plugin(Object target) { return Plugin.wrap(target, this); } public void setProperties(Properties properties) { } }

 通过上面发现Plugin这个类很重要,接下来在看看它的源码,代码如下:

public class Plugin implements InvocationHandler { private Object target; private Interceptor interceptor; private Map<Class<?>, Set<Method>> signatureMap; private Plugin(Object target, Interceptor interceptor, Map<Class<?>, Set<Method>> signatureMap) { this.target = target; this.interceptor = interceptor; this.signatureMap = signatureMap; } public static Object wrap(Object target, Interceptor interceptor) { // Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor); Class<?> type = target.getClass(); Class<?>[] interfaces = getAllInterfaces(type, signatureMap); if (interfaces.length > 0) { // 创建JDK动态代理对象 return Proxy.newProxyInstance( type.getClassLoader(), interfaces, new Plugin(target, interceptor, signatureMap)); } return target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { Set<Method> methods = signatureMap.get(method.getDeclaringClass()); //判断执行方法是否需要拦截 if (methods != null && methods.contains(method)) { //调用Interceptor的intercept()方法 return interceptor.intercept(new Invocation(target, method, args)); } return method.invoke(target, args); } catch (Exception e) { throw ExceptionUtil.unwrapThrowable(e); } } //....... }

3.Mybatis可以拦截哪些接口?

要知道这个问题 ,看看Configuration的源码就行了,代码如下:

public class Configuration { //... public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) { ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql); parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler); return parameterHandler; } public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler, ResultHandler resultHandler, BoundSql boundSql) { ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds); resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler); return resultSetHandler; } public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql); statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler); return statementHandler; } public Executor newExecutor(Transaction transaction) { return newExecutor(transaction, defaultExecutorType); } public Executor newExecutor(Transaction transaction, ExecutorType executorType) { executorType = executorType == null ? defaultExecutorType : executorType; executorType = executorType == null ? ExecutorType.SIMPLE : executorType; Executor executor; if (ExecutorType.BATCH == executorType) { executor = new BatchExecutor(this, transaction); } else if (ExecutorType.REUSE == executorType) { executor = new ReuseExecutor(this, transaction); } else { executor = new SimpleExecutor(this, transaction); } if (cacheEnabled) { executor = new CachingExecutor(executor); } executor = (Executor) interceptorChain.pluginAll(executor); return executor; } //... }

从上面可以看出,Mybatis只拦截ParameterHandler、ResultSetHandler、StatementHandler、Executor共4个接口对象内的方法。 

 

 

 

 

 

 

 

 

转载请注明原文地址: https://www.6miu.com/read-5029395.html

最新回复(0)