1、Interceptor

2、插件配置解析

配置文件中解析plugins结点,在子结点中获取interceptor属性及子结点的属性结点。添加到配置文件中的InterceptorChain中

private void pluginElement(XNode parent) throws Exception {if (parent != null) {for (XNode child : parent.getChildren()) {String interceptor = child.getStringAttribute("interceptor");Properties properties = child.getChildrenAsProperties();Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).getDeclaredConstructor().newInstance();interceptorInstance.setProperties(properties);configuration.addInterceptor(interceptorInstance);}}}

3、拦截原理

拦截Executor方法,ParameterHandler方法,ResultSetHandler方法,StatementHandler方法。在创建对应实例时,会通过InterceptorChain.pluginAll方法遍历interceptors集合,并调用其中每个元素的plugin方法来创建动态代理。

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 Object pluginAll(Object target) {for (Interceptor interceptor : interceptors) {target = interceptor.plugin(target);}return target;}

Interceptor.plugin方法是通过Plugin.wrap静态方法创建代理对象。

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;}

@Intercepts注解定义为

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Intercepts {Signature[] value();
}

@Signature注解定义为

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({})
public @interface Signature {Class<?> type();String method();Class<?>[] args();
}

在封装时先获取Interceptor上定义的注解@Intercepts,获取@Signature注解数组,遍历Signature获取,根据注解中的type,method,args属性获取拦截器支持拦截的方法。

private static Map<Class<?>, Set<Method>> getSignatureMap(Interceptor interceptor) {Intercepts interceptsAnnotation = interceptor.getClass().getAnnotation(Intercepts.class);// issue #251if (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 = MapUtil.computeIfAbsent(signatureMap, 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]);}

在调用时会判断签名中是否有Method的声明类,如果有则判断方法中是否包含此方法,有则将目录对象,方法及参数封装成Invacation,通过Interceptor.intercept来处理拦截逻辑。如果没有,则直接调用目录对象方法。

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)) {return interceptor.intercept(new Invocation(target, method, args));}return method.invoke(target, args);} catch (Exception e) {throw ExceptionUtil.unwrapThrowable(e);}}

mybatis中的插件相关推荐

  1. 在控制台打印sql语句的办法(MyBatis Log Plugin插件的安装与使用)

    MyBatis Log Plugin插件的安装与使用 在使用Mybatis开发项目时,由于避免出现SQL注入,大部分情况下都是使用#{}占位符的方式传参.如果SQL比较复杂,参数又很多的话,要通过日志 ...

  2. 10、mybatis中缓存的使用

    对于初学者,如何进行mybatis的学习呢?我总结了几点,会慢慢的更新出来.首先大家需要了解mybatis是什么.用mybatis来做什么.为什么要用mybatis.有什么优缺点:当知道了为什么的时候 ...

  3. 9、mybatis中动态sql的使用

    对于初学者,如何进行mybatis的学习呢?我总结了几点,会慢慢的更新出来.首先大家需要了解mybatis是什么.用mybatis来做什么.为什么要用mybatis.有什么优缺点:当知道了为什么的时候 ...

  4. 6、mybatis中的sql映射文件详解(1)

    对于初学者,如果进行mybatis的学习呢?我总结了几点,会慢慢的更新出来.首先大家需要了解mybatis是什么.用mybatis来做什么.为什么要用mybatis.有什么优缺点:当知道了为什么的时候 ...

  5. Mybatis中的updateByPrimaryKeySelective()和updateByPrimaryKey()

    Mybatis中的updateByPrimaryKeySelective和updateByPrimaryKey 区别 一些通用Mapper踩的坑 区别 updateByPrimaryKeySelect ...

  6. Spring Boot系列教程八: Mybatis使用分页插件PageHelper

    一.前言 上篇博客中介绍了spring boot集成mybatis的方法,基于上篇文章这里主要介绍如何使用分页插件PageHelper.在MyBatis中提供了拦截器接口,我们可以使用PageHelp ...

  7. mysql序列 mybatis_MySQL实现序列(Sequence)效果以及在Mybatis中如何使用这种策略

    前言: 在oracle中一般使用序列(Sequence)来处理主键字段,在MySQL中是没有序列的,但是MySQL有提供了自增长(increment)来实现类似的目的,但也只是自增,而不能设置步长.开 ...

  8. mybatis中文文档_成神之路!缓存+MyBatis+MySQL+Spring全家桶+分布式技术实战合集

    最近花了很长的时间去搜罗Java核心技术好文,我把每个Java核心技术的优选文章都整理成了一个又一个的文档.昨天也是终于全部整理好了,今天就把这些东西分享给老铁们,也能为老铁们省去不少麻烦,想学什么技 ...

  9. 使用 MyBatis 的 Maven 插件生成代码

    我们无需手动编写 实体类.DAO.XML 配置文件,只需要使用 MyBatis 提供的一个 Maven 插件就可以自动生成所需的各种文件便能够满足基本的业务需求,如果业务比较复杂只需要修改相关文件即可 ...

最新文章

  1. spingmvc的一些简单理解和记录
  2. WCF学习- 基础概念
  3. 简单接触一下scikit-learn
  4. SAP Spartacus visible-focus是如何施加到HTML element上的
  5. Linux以oracle用户登录,Linux_oracle 10G for linux常用命令,首先以Oracle用户登录1、 - phpStudy...
  6. php3级分类,关于php非递归三级分类输出json数据
  7. spark eventLoop模型
  8. MySQL Encryption and Compression Functions(加密)
  9. Javascript提升阶段学习
  10. Python数据结构实战——双向链表(DoublyLinkedList)
  11. 快速清理Exchange 2003中的SMTP队列
  12. 在SQLServer2005中使用全文搜索
  13. 你知道哪些苹果自家应用采用 Swift 语言编写吗?
  14. Python 正则表达式大全
  15. visio作图的一系列坑
  16. 利用saopanel系统的UDP转发模式破解校园网
  17. 愚人节就是要搞怪!微信公众号图文应该这样排版!
  18. 断网重启路由器就好_为什么总是断网重启路由器就好了
  19. Netty in Action 翻译说明
  20. 【Hexo】记录NexT主题美化及域名配置(图示详解)

热门文章

  1. [转载]在中文Windows环境下,控制台窗口中也可以用特殊符号拼出漂亮的表格来。...
  2. python是通用编程语言吗-2020年,编程语言将不再只属于程序员,尤其是这门语言...
  3. python画二维散点图-python3实现绘制二维点图
  4. python安装pip-python2.7 安装pip的方法步骤(管用)
  5. python画直方图成绩分析-python plotly绘制直方图实例详解
  6. python 画三维函数图-Python之Numpy:二元函数绘制/三维数据可视化/3D
  7. python面试题及答案-Python 45道基本面试题及答案 (新手非常有用)
  8. python爬虫能干什么-python爬虫能干什么
  9. python1000个常用代码-1000个常用的Python库和示例代码
  10. python详细安装教程linux-Python 环境安装步骤