一、Mybatis插件Plugin解析
二、Mybatis插件模拟代码
Mybatis插件能对4大对象进行代理拦截 。 Executor、StatementHandler、ParameterHandler、ResultSetHandler
相关代码都在Configuration中
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; } |
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 class InterceptorChain { // 在解析mybatis-config.xml的时候,会将拦截器存入interceptors private final List<Interceptor> interceptors = new ArrayList<>(); public Object pluginAll(Object target) { for (Interceptor interceptor : interceptors) { // 如果有多个拦截器 ,第一个拦截器生成target的代理对象targetProxy0 , // 第二个拦截器生成targetProxy0的代理对象targetProxy1 , // 第三个拦截器生成targetProxy1的代理对象targetProxy2 , 依此类推…… // 所以代理是可以被代理的。 // 调用时执行顺序是先调用最外层的,依次向内,最终才会调用目标方法 target = interceptor.plugin(target); } return target; } // 在解析mybatis-config.xml的时候,会调用此方法 public void addInterceptor(Interceptor interceptor) { interceptors.add(interceptor); } public List<Interceptor> getInterceptors() { return Collections.unmodifiableList(interceptors); } }
import org.apache.ibatis.builder.StaticSqlSource; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.executor.statement.StatementHandler; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.SqlSource; import org.apache.ibatis.plugin.*; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; import java.lang.reflect.Field; import java.sql.Connection; import java.util.Properties; @Intercepts({@Signature(type = StatementHandler.class,method = "prepare", args = {Connection.class, Integer.class}) }) public class MyPageInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { //在这里处理自己的业务逻辑 // ……………… // 执行被拦截方法 return invocation.proceed(); } @Override public Object plugin(Object target) { // 关键代码 return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { } }
package org.apache.ibatis.plugin; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.apache.ibatis.reflection.ExceptionUtil; public class Plugin implements InvocationHandler { private final Object target; private final Interceptor interceptor; private final 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) { 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 { // 判断当前method是否需要被拦截 Set<Method> methods = signatureMap.get(method.getDeclaringClass()); if (methods != null && methods.contains(method)) { return interceptor.intercept(new Invocation(target, method, args)); } return method.invoke(target, args); } catch (Exception e) { throw ExceptionUtil.unwrapThrowable(e); } } private static Map<Class<?>, Set<Method>> getSignatureMap(Interceptor interceptor) { Intercepts interceptsAnnotation = interceptor.getClass().getAnnotation(Intercepts.class); // issue #251 if (interceptsAnnotation == null) { throw new PluginException("No @Intercepts annotation was found in interceptor " + interceptor.getClass().getName()); } Signature[] sigs = interceptsAnnotation.value(); Map<Class<?>, Set<Method>> signatureMap = new HashMap<>(); for (Signature sig : sigs) { Set<Method> methods = signatureMap.computeIfAbsent(sig.type(), k -> new HashSet<>()); try { Method method = sig.type().getMethod(sig.method(), sig.args()); methods.add(method); } catch (NoSuchMethodException e) { throw new PluginException("Could not find method on " + sig.type() + " named " + sig.method() + ". Cause: " + e, e); } } return signatureMap; } private static Class<?>[] getAllInterfaces(Class<?> type, Map<Class<?>, Set<Method>> signatureMap) { Set<Class<?>> interfaces = new HashSet<>(); while (type != null) { for (Class<?> c : type.getInterfaces()) { if (signatureMap.containsKey(c)) { interfaces.add(c); } } type = type.getSuperclass(); } return interfaces.toArray(new Class<?>[0]); } }
如果配置了相应的拦截器,在Executor、StatementHandler、ParameterHandler、ResultSetHandler调用其方法时,会先执行Plugin的invoke方法(动态代理设置的回调类为Plugin) , 确定该方法被拦截,然后执行Interceptor中的intercept方法 , 所有代理方法执行完成后,就执行目标方法。
package com.example.demo.proxy; import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.List; public class PluginDemo { public static void main(String[] args) { UserService userService = new UserServiceImpl(); userService = (UserService) getProxy(userService); String doBusiness = userService.doBusiness(1001); System.out.println("doBusiness : " + doBusiness); } public static Object getProxy(Object obj) { List<Interceptor> list = new ArrayList<Interceptor>(); // 3层代理 list.add(new MyInterceptor1()); list.add(new MyInterceptor2()); list.add(new MyInterceptor3()); for (Interceptor interceptor : list) { obj = newProxy(obj, interceptor); } return obj; } public static Object newProxy(Object obj, Interceptor interceptor) { return Proxy.newProxyInstance(PluginDemo.class.getClassLoader(), obj.getClass().getInterfaces(), new MyInvocation(obj, interceptor)); } }
package com.example.demo.proxy; interface UserService { String doBusiness(int id); String getMsg(); void setMsg(String msg); }
package com.example.demo.proxy; public class UserServiceImpl implements UserService { private String msg; public UserServiceImpl() { this.msg = "UserServiceImpl msg " ; } @Override public String doBusiness(int id) { return "name : " + id; } @Override public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
package com.example.demo.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * 动态代理的回调类 */ public class MyInvocation implements InvocationHandler { private Interceptor interceptor; private Object obj; public MyInvocation(Object obj, Interceptor interceptor) { this.interceptor = interceptor; this.obj = obj; } public MyInvocation() { } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName() ; /** * 拦截指定方法,不然会拦截所有的方法,执行就会很乱 */ if (interceptor != null && "doBusiness".equals(methodName)) { return interceptor.intercept(obj, method, args); } else { return method.invoke(obj, args); } } }
package com.example.demo.proxy; import java.lang.reflect.Method; public interface Interceptor { public Object intercept(Object obj, Method method, Object[] args); }
package com.example.demo.proxy; import java.lang.reflect.Method; public class MyInterceptor1 implements Interceptor { @Override public Object intercept(Object obj, Method method, Object[] args) { UserService u = (UserService) obj; System.out.println("MyInterceptor1 " + u.getMsg()); u.setMsg("MyInterceptor1 msg"); try { return method.invoke(obj, args); } catch (Exception e) { e.printStackTrace(); } return null; } }
package com.example.demo.proxy; import java.lang.reflect.Method; public class MyInterceptor2 implements Interceptor { @Override public Object intercept(Object obj, Method method, Object[] args) { UserService u = (UserService) obj; System.out.println("MyInterceptor2 " + u.getMsg()); u.setMsg("MyInterceptor2 msg"); try { return method.invoke(obj, args); } catch (Exception e) { e.printStackTrace(); } return null; } }
package com.example.demo.proxy; import java.lang.reflect.Method; public class MyInterceptor3 implements Interceptor { @Override public Object intercept(Object obj, Method method, Object[] args) { UserService u = (UserService) obj; System.out.println("MyInterceptor3 " + u.getMsg()); u.setMsg("MyInterceptor3 msg"); try { return method.invoke(obj, args); } catch (Exception e) { e.printStackTrace(); } return null; } }
执行主类PluginDemo, 打印:
MyInterceptor3 UserServiceImpl msg MyInterceptor2 MyInterceptor3 msg MyInterceptor1 MyInterceptor2 msg doBusiness : name : 1001 |