欢迎您访问365答案网,请分享给你的朋友!
生活常识 学习资料

mybatis插件逻辑

时间:2023-08-07
自定义实现插件

自定义插件要实现mybatis的插件接口 Interceptor

public interface Interceptor { // 执行拦截逻辑的方法 Object intercept(Invocation invocation) throws Throwable; // 决定是否触发 intercept()方法,如果该插件是拦截对应方法,则返回该类的代理对象 default Object plugin(Object target) { return Plugin.wrap(target, this); } // 根据配置 初始化 Intercept 对象 default void setProperties(Properties properties) { // NOP }}

自定义拦截器
@Intercepts({
@Signature(
type = Executor.class // 需要拦截的类型
, method = “query” // 需要拦截的方法
// args 中指定 被拦截方法的 参数列表
, args = {MappedStatement.class, Object.class, RowBounds.class,
ResultHandler.class}
),
@Signature(
type = Executor.class
, method = “close”
, args = {boolean.class}
)
})
public class MyInterceptor implements Interceptor {
public Object intercept(Invocation invocation) throws Throwable {
System.out.println(“被拦截方法执行前打印。。。”);
Object object = invocation.proceed();
System.out.println(“被拦截方法执行后打印。。。”);
return object;

}public Object plugin(Object target) { return Plugin.wrap(target, this);}public void setProperties(Properties properties) {}

}

插件配置初始化

插件拦截的4个类:Excutor ParameterHandler StatementHandler ResultSetHandler

初始化
SqlSessionFactoryBuilder

public SqlSessionFactory build(Reader reader, String environment, Properties properties) { try { // 读取配置文件 XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties); // 解析配置文件得到Configuration对象 创建DefaultSqlSessionFactory对象 return build(parser.parse()); } catch (Exception e) { throw ExceptionFactory.wrapException("Error building SqlSession.", e); } finally { ErrorContext.instance().reset(); try { reader.close(); } catch (IOException e) { // Intentionally ignore、Prefer previous error. } } }

XMLConfigBuilder
插件解析:pluginElement(root.evalNode(“plugins”));,最终得到
InterceptorsChain 对象,里面对插件进行管理

private void parseConfiguration(XNode root) { try { //issue #117 read properties first // 对于全局配置文件各种标签的解析 propertiesElement(root.evalNode("properties")); // 解析 settings 标签 Properties settings = settingsAsProperties(root.evalNode("settings")); // 读取文件 loadCustomVfs(settings); // 日志设置 loadCustomLogImpl(settings); // 类型别名 typeAliasesElement(root.evalNode("typeAliases")); // 插件 pluginElement(root.evalNode("plugins")); // 用于创建对象 objectFactoryElement(root.evalNode("objectFactory")); // 用于对对象进行加工 objectWrapperFactoryElement(root.evalNode("objectWrapperFactory")); // 反射工具箱 reflectorFactoryElement(root.evalNode("reflectorFactory")); // settings 子标签赋值,默认值就是在这里提供的 >> settingsElement(settings); // read it after objectFactory and objectWrapperFactory issue #631 // 创建了数据源 >> environmentsElement(root.evalNode("environments")); databaseIdProviderElement(root.evalNode("databaseIdProvider")); typeHandlerElement(root.evalNode("typeHandlers")); // 解析引用的Mapper映射器 mapperElement(root.evalNode("mappers")); } catch (Exception e) { throw new BuilderException("Error parsing SQL Mapper Configuration、Cause: " + e, e); } }

InterceptorsChain

public class InterceptorChain { // 保存所有的 Interceptor 也就我所有的插件是保存在 Interceptors 这个List集合中的 private final List interceptors = new ArrayList<>(); //根据拦截器集合的拦截配置对某一个对象的进行拦截(反射代理) public Object pluginAll(Object target) { for (Interceptor interceptor : interceptors) { // 获取拦截器链中的所有拦截器 target = interceptor.plugin(target); // 创建对应的拦截器的代理对象 } return target; } public void addInterceptor(Interceptor interceptor) { interceptors.add(interceptor); } public List getInterceptors() { return Collections.unmodifiableList(interceptors); }}

代理方法的执行 plugin

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { // 获取当前方法所在类或接口中,可被当前Interceptor拦截的方法 Set 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); } }

插件的关键类

Interceptor :插件接口,用户自定义插件需要实现该接口
InterceptroChain :插件链管理:应用中所有的插件在初始化节点都会解析放到该对象中进行管理
Plugin :插件触发管理类,负责对插件对象进行代理包装,同时实现invoke调用逻辑,实现多个插件的层层调用
Invocation:调用方法的包装对象,封装调用方法的信息
@Interceptors 拦截的配置注解
@Signature :拦截方法签名注解

Copyright © 2016-2020 www.365daan.com All Rights Reserved. 365答案网 版权所有 备案号:

部分内容来自互联网,版权归原作者所有,如有冒犯请联系我们,我们将在三个工作时内妥善处理。