拦截器核心类:
先来看看jdk的代理是如何实现的:
java.lang.reflect.InvocationHandler java.lang.reflect.Proxy public class MyInvocationHandler implements InvocationHandler{ private Object target; public MyInvocationHandler(Object target) { super(); this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println(Object.class); System.out.println(method.getDeclaringClass()); System.out.println("------------------before------------------"); // 执行目标对象的方法 Object result = method.invoke(target, args); // 在目标对象的方法执行之后简单的打印一下 System.out.println("-------------------after------------------"); return result; } public Object getProxy() { return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(), this); } }
测试:
UserService userService = new UserServiceImpl(); // 实例化InvocationHandler MyInvocationHandler invocationHandler = new MyInvocationHandler(userService); // 根据目标对象生成代理对象 UserService proxy = (UserService) invocationHandler.getProxy(); // 调用代理对象的方法 proxy.add();
下面就看一下mybatis的拦截器是如何实现的:
在org.apache.ibatis.plugin 下有拦截器的核心代码
注解类 Interceptors 和 Signature
Ivocation接口是要求自定义的拦截器必须继承自这个接口重新他的方法
Plugin 这个类继承与InvocationHandler
InterceptorChain 是一个拦截器连,既然是连儿那么里面一定有结合来存储和注册拦截器的方法
现在我们先来用mybatis的拦截器做一个测试。
import java.util.HashMap; import java.util.Map; import java.util.Properties; import org.apache.ibatis.plugin.Interceptor; import org.apache.ibatis.plugin.Intercepts; import org.apache.ibatis.plugin.Invocation; import org.apache.ibatis.plugin.Plugin; import org.apache.ibatis.plugin.Signature; import org.junit.Test; public class PluginTest { public static void main(String[] args) { Map map = new HashMap(); map = (Map) new AlwaysMapPlugin().plugin(map); map.put("asdfadfs","ddddd"); System.out.println(map.getClass()); System.out.println( map.get("asdfadfs")); } @Intercepts({ @Signature(type = Map.class, method = "get", args = {Object.class})}) public static class AlwaysMapPlugin implements Interceptor { //连接器触发的方法 public Object intercept(Invocation invocation) throws Throwable { invocation.proceed(); System.out.println("拦截器被触发"); return "Always"; } //创建代理类 public Object plugin(Object target) { return Plugin.wrap(target, this); } public void setProperties(Properties properties) { } } }
上面的代码中有我们自定义的拦截器AlwaysMapPlugin ,它继承自Interceptor 实现了它的方法。
intercept 这个方法是在触发自定义拦截器注解中的类和方法的时候触发的。
Invocation 参数中定义了
private Object target; 目标类,也就是测试中的map
private Method method; 方法类 注解中的get方法
private Object[] args; 方法参数
plugin 这个方法中使用了Plugin这个代理类,Plugin.wrap(target, this); 返回一个拦截器代码,你可以测试一下 System.out.println(map.getClass());控制台输出class $Proxy5 是一个Map的代理对象。
整个拦截器很简单,唯一Plugin.wrap(target, this);这个类的调用还没有被看到,也是拦截器的核心。
public class Plugin implements InvocationHandler { private Object target; private Interceptor interceptor; private Map<Class<?>, Set<Method>> signatureMap; private Plugin(Object target, Interceptor interceptor, Map<Class<?>, Set<Method>> signatureMap) { .......... } //静态方法获取代理类 public static Object wrap(Object target, Interceptor interceptor) { ....... 返回代理类 return Proxy.newProxyInstance( type.getClassLoader(),//classloader interfaces,//工具类中处理的接口 new Plugin(target, interceptor, signatureMap)//实例化代理对象 ); .......... } //代理方法 执行被代理方法中的intercept实现 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {......... } //工具方法 获取自定义拦截器中注解中定义的接口类 private static Map<Class<?>, Set<Method>> getSignatureMap(Interceptor interceptor) {......... } //工具方法 type.getInterfaces() //type 是被代理对象 signatureMap 是上面的工具方法获取的要代理的接口类列表 // 方法返回自定义连接器中定义的接口和代理对象实例的接口列表 //说白了:这个方法就是来判断new AlwaysMapPlugin().plugin(map); 这个map实例的接口 //是否有 @Signature(type = Map.class, 这里的Map接口。 private static Class<?>[] getAllInterfaces(Class<?> type, Map<Class<?>, Set<Method>> signatureMap) {...... } }
如果要添加上连接器链:测试代码这样写
Map map = new HashMap(); InterceptorChain chain = new InterceptorChain(); //注册拦截器 chain.addInterceptor(new CustomInterceptor()); //获取代理类 map = (Map)chain.pluginAll(map); map.get("ddd");
那么我们来看看mybatis中的拦截器是合适调用的
操作数据库的步骤是 获取config资源,构建sqlsessionFactory,获取sqlsession,操作数据库。
我们在xml文件中定义好的拦截器就是在构建Configuration的时候注册到org.apache.ibatis.session.Configuration类中去的。在这个类里面有我们熟悉的InterceptorChain 拦截器连儿。
什么时候执行这个连接器呢,我们要看一下它的源码。
//方法1 public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) { ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql); parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler); return parameterHandler; } //方法2 public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler, ResultHandler resultHandler, BoundSql boundSql) { ResultSetHandler resultSetHandler = mappedStatement.hasNestedResultMaps() ? new NestedResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds) : new FastResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds); resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler); return resultSetHandler; } //方法3 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; } //方法4 public Executor newExecutor(Transaction transaction, ExecutorType executorType, boolean autoCommit) { 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, autoCommit); } executor = (Executor) interceptorChain.pluginAll(executor); return executor; }
还记得我们自定义的例子中 map = (Map)chain.pluginAll(map); 返回代理类对象
这里的四个方法其实就是限制了,mybatis 中拦截器可以连接的接口,Executor,StatementHandler, ResultSetHandler,ParameterHandler ( 因为:interceptorChain.pluginAll(接口类型))
相关推荐
MyBatis是一款流行的Java...总的来说,MyBatis源码分析思维导图会涵盖MyBatis的各个关键组件、工作流程、特性以及扩展机制。通过深入学习和理解这些内容,开发者能够更好地利用MyBatis进行数据库操作,并优化其性能。
通过本套"mybatis源码分析视频",学习者可以跟随视频逐步解析MyBatis的源码,了解这些核心组件如何协同工作,以及如何根据实际需求进行定制和优化。同时,文档可能包含详细的步骤说明、示例代码和关键知识点解析,...
通过实现Interceptor接口并注册,开发者可以自定义拦截器,对Executor、StatementHandler、ParameterHandler和ResultSetHandler的行为进行增强。 总的来说,《MyBatis源码详解学习》这份资料涵盖了MyBatis框架的...
"CXF3.1.16 +Spring4 +MyBatis + Maven自定义拦截器 WebService实例源码下载" 这个标题揭示了该项目的核心技术栈,包括: 1. CXF 3.1.16:这是一个开源的服务框架,用于构建和开发服务,支持SOAP和RESTful Web服务...
MyBatis 分页拦截器是一种优化数据库查询性能的工具,它允许我们在不修改原有业务代码的情况下,实现对数据库查询结果的分页处理。在大型Web应用中,分页功能是必不可少的,因为它可以帮助用户更有效地浏览和管理...
2. **MyBatis源码解析**: `mybatis-2.3.5-sources.jar`包含了MyBatis的源代码,这对于我们理解框架内部工作流程极其有价值。例如,你可以看到`SqlSession`、`SqlSessionFactory`和`Mapper`接口的实现,以及如何...
11. MyBatis插件:通过拦截器机制,用户可以自定义插件来扩展MyBatis的功能,如日志、性能分析等。 在分析MyBatis源码时,开发者通常会关注以下几个方面: 1. 源码结构:了解MyBatis的模块划分,如sql解析、执行、...
《MyBatis源码分析与实战应用》 在IT行业中,MyBatis作为一个轻量级的持久层框架,因其灵活性和高效性而被广泛应用。它将SQL语句与Java代码相结合,提供了比传统JDBC更方便的数据操作方式。本文将深入探讨MyBatis的...
标题中的"MyBatis源码包"指的是包含了MyBatis框架的源代码文件,这对于开发者来说是一份宝贵的学习资源。通过阅读源码,开发者可以深入理解MyBatis的工作原理,学习如何设计和实现一个高效的ORM框架,以及如何处理...
10. **插件支持**:MyBatis允许用户自定义插件,拦截Executor、StatementHandler、ParameterHandler和ResultSetHandler的关键方法,进行增强或监控。 通过研究MyBatis 3.2.7的源码,开发者可以理解其执行流程,学习...
在深入MyBatis源码之前,我们需要了解一些基础概念。MyBatis的核心组件包括SqlSessionFactory、SqlSession和Executor。SqlSessionFactory是创建SqlSession的工厂,SqlSession是与数据库交互的主要接口,而Executor则...
此外,学习Mybatis源码还能帮助你理解如何自定义插件,比如Interceptor拦截器,它可以插入到Executor、StatementHandler、ParameterHandler、ResultSetHandler的执行链中,实现自定义功能。 总的来说,这个实例代码...
### MyBatis拦截器原理与应用 #### 一、MyBatis拦截器概述 MyBatis作为一款优秀的持久层框架,提供了丰富的扩展机制,其中一项重要特性便是插件(plugin)功能,实际上指的是拦截器功能。通过拦截器,开发人员可以在...
【标题】"Mybatis系列教程Mybatis源码剖析共15页.pdf" 是一份详细的Mybatis框架源码解析教程,涵盖了Mybatis的核心概念和技术细节。这份教程深入浅出地介绍了Mybatis如何工作,以及其背后的代码实现,对于理解...
在 PageHelper 插件中,主要通过拦截器机制实现分页功能。当执行 SQL 查询时,`PageInterceptor` 会拦截到这个过程,然后根据分页参数(如 `@Page` 注解)动态生成分页 SQL。在 MySQL 中,这通常意味着在原始 SQL ...
- MyBatis提供了一个强大的插件机制,用户可以自定义拦截器实现SQL执行前后的增强功能,如日志、性能分析等。 7. MyBatis的Spring整合 - MyBatis与Spring整合后,可以使用Spring的事务管理,简化了事务控制和依赖...
MyBatis允许开发者自定义拦截器,通过Interceptor接口实现,可以拦截SQLSession的某些操作,例如添加日志、性能监控等。 七、事务管理 MyBatis支持手动和自动两种事务管理方式。手动模式下,开发者需在代码中显式...
SSM框架,全称为Spring、Spring MVC和MyBatis,是Java开发中广泛使用的轻量级Web...提供的"互联网轻量级SSM框架解密:Spring、Spring MVC、MyBatis源码深度剖析.pdf"文档,无疑是一份宝贵的参考资料,值得深入研究。
`MyBatis_09_source`可能涉及到了MyBatis源码的深度解析,有助于开发者理解MyBatis内部的工作流程,如SQL映射的解析、参数绑定、结果映射等核心过程。 `mybatis.dtd`文件是MyBatis的文档类型定义(DTD),它是XML...
7. **插件机制**:了解MyBatis的拦截器插件,如何自定义插件实现日志、性能统计等功能。 8. **缓存的实现**:查看MyBatis如何实现本地缓存和二级缓存,以及如何配置缓存策略。 通过分析这些源码,初学者不仅可以...