Mybatis插件Plugin解析


    

一、Mybatis插件Plugin解析

二、Mybatis插件模拟代码

   

一、Mybatis插件Plugin解析

     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方法 , 所有代理方法执行完成后,就执行目标方法。




二、Mybatis插件模拟代码

image.png

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



Mybatis插件Plugin

2021.06.02 00:30

https://www.meihaocloud.com.com/1075.html , 欢迎转载,请在文章页标出原文连接 !


Copyright © 2020 千夕网 联系站长

粤公网安备 44030302001408号 粤ICP备19099833号-1