mybatis中的插件
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中的插件相关推荐
- 在控制台打印sql语句的办法(MyBatis Log Plugin插件的安装与使用)
MyBatis Log Plugin插件的安装与使用 在使用Mybatis开发项目时,由于避免出现SQL注入,大部分情况下都是使用#{}占位符的方式传参.如果SQL比较复杂,参数又很多的话,要通过日志 ...
- 10、mybatis中缓存的使用
对于初学者,如何进行mybatis的学习呢?我总结了几点,会慢慢的更新出来.首先大家需要了解mybatis是什么.用mybatis来做什么.为什么要用mybatis.有什么优缺点:当知道了为什么的时候 ...
- 9、mybatis中动态sql的使用
对于初学者,如何进行mybatis的学习呢?我总结了几点,会慢慢的更新出来.首先大家需要了解mybatis是什么.用mybatis来做什么.为什么要用mybatis.有什么优缺点:当知道了为什么的时候 ...
- 6、mybatis中的sql映射文件详解(1)
对于初学者,如果进行mybatis的学习呢?我总结了几点,会慢慢的更新出来.首先大家需要了解mybatis是什么.用mybatis来做什么.为什么要用mybatis.有什么优缺点:当知道了为什么的时候 ...
- Mybatis中的updateByPrimaryKeySelective()和updateByPrimaryKey()
Mybatis中的updateByPrimaryKeySelective和updateByPrimaryKey 区别 一些通用Mapper踩的坑 区别 updateByPrimaryKeySelect ...
- Spring Boot系列教程八: Mybatis使用分页插件PageHelper
一.前言 上篇博客中介绍了spring boot集成mybatis的方法,基于上篇文章这里主要介绍如何使用分页插件PageHelper.在MyBatis中提供了拦截器接口,我们可以使用PageHelp ...
- mysql序列 mybatis_MySQL实现序列(Sequence)效果以及在Mybatis中如何使用这种策略
前言: 在oracle中一般使用序列(Sequence)来处理主键字段,在MySQL中是没有序列的,但是MySQL有提供了自增长(increment)来实现类似的目的,但也只是自增,而不能设置步长.开 ...
- mybatis中文文档_成神之路!缓存+MyBatis+MySQL+Spring全家桶+分布式技术实战合集
最近花了很长的时间去搜罗Java核心技术好文,我把每个Java核心技术的优选文章都整理成了一个又一个的文档.昨天也是终于全部整理好了,今天就把这些东西分享给老铁们,也能为老铁们省去不少麻烦,想学什么技 ...
- 使用 MyBatis 的 Maven 插件生成代码
我们无需手动编写 实体类.DAO.XML 配置文件,只需要使用 MyBatis 提供的一个 Maven 插件就可以自动生成所需的各种文件便能够满足基本的业务需求,如果业务比较复杂只需要修改相关文件即可 ...
最新文章
- spingmvc的一些简单理解和记录
- WCF学习- 基础概念
- 简单接触一下scikit-learn
- SAP Spartacus visible-focus是如何施加到HTML element上的
- Linux以oracle用户登录,Linux_oracle 10G for linux常用命令,首先以Oracle用户登录1、 - phpStudy...
- php3级分类,关于php非递归三级分类输出json数据
- spark eventLoop模型
- MySQL Encryption and Compression Functions(加密)
- Javascript提升阶段学习
- Python数据结构实战——双向链表(DoublyLinkedList)
- 快速清理Exchange 2003中的SMTP队列
- 在SQLServer2005中使用全文搜索
- 你知道哪些苹果自家应用采用 Swift 语言编写吗?
- Python 正则表达式大全
- visio作图的一系列坑
- 利用saopanel系统的UDP转发模式破解校园网
- 愚人节就是要搞怪!微信公众号图文应该这样排版!
- 断网重启路由器就好_为什么总是断网重启路由器就好了
- Netty in Action 翻译说明
- 【Hexo】记录NexT主题美化及域名配置(图示详解)
热门文章
- [转载]在中文Windows环境下,控制台窗口中也可以用特殊符号拼出漂亮的表格来。...
- python是通用编程语言吗-2020年,编程语言将不再只属于程序员,尤其是这门语言...
- python画二维散点图-python3实现绘制二维点图
- python安装pip-python2.7 安装pip的方法步骤(管用)
- python画直方图成绩分析-python plotly绘制直方图实例详解
- python 画三维函数图-Python之Numpy:二元函数绘制/三维数据可视化/3D
- python面试题及答案-Python 45道基本面试题及答案 (新手非常有用)
- python爬虫能干什么-python爬虫能干什么
- python1000个常用代码-1000个常用的Python库和示例代码
- python详细安装教程linux-Python 环境安装步骤