java MyBatis拦截器Inteceptor详细介绍_java

有许多java初学者对于MyBatis拦截器Inteceptor不是很了解,在这里我来为各位整理下篇关于java中MyBatis拦截器Inteceptor详解,

本文主要分析MyBatis的插件机制,实际就是Java动态代理实现的责任链模式实现。

根据官方文档。Mybatis只允许拦截以下方法,这个决定写拦截器注解签名参数。

 代码如下 

Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
ParameterHandler (getParameterObject, setParameters)
ResultSetHandler (handleResultSets, handleOutputParameters)
StatementHandler (prepare, parameterize, batch, update, query)

拦截处理的源码如下,其中interceptorChain.pluginAll(..)即为织入自定义拦截器:

代码如下 

/* org.apache.ibatis.session.Configuration类中方法 */
public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
  ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
  /* 拦截ParameterHandler*/
  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 = (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 = (StatementHandler) interceptorChain.pluginAll(statementHandler);
  return statementHandler;
}
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 = (Executor) interceptorChain.pluginAll(executor);
 return executor;
}

实现一个自定义拦截器只需实现Interceptor接口即可,大致代码如下:

 代码如下 

/* 注解表明要拦截哪个接口的方法及其参数 */
@Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class }) })
public class YourInterceptor implements Interceptor{
 public Object intercept(Invocation invocation) throws Throwable{
  doSomeThing();
  /* 注:此处实际上使用Invocation.proceed()方法完成interceptorChain链的遍历调用(即执行所有注册的Interceptor的intercept方法),到最终被代理对象的原始方法调用 */
  return invocation.proceed();
 }
  /*生成成对目标target的代理,而@Intercepts的注解是在Plugin.wrap中用到*/
 @Override
 public Object plugin(Object target){
   /* 当目标类是StatementHandler类型时,才包装目标类,不做无意义的代理 */
  return (target instanceof StatementHandler)?Plugin.wrap(target, this):target;
 }
  /*用于设置自定义的拦截器配置参数*/
 @Override
 public void setProperties(Properties properties){
 }
}

其中,拦截调用的代码均在Plugin.wrap中:

代码如下

/* org.apache.ibatis.plugin.Plugin类 */
public class Plugin implements InvocationHandler {
 /* 省略代码... */
 public static Object wrap(Object target, Interceptor interceptor) {
  /* 此处即为获取Interceptor的注解签名 */
  Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
  Class<?> type = target.getClass();
  /* 获取拦截目标类相匹配的接口 */
  Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
  if (interfaces.length > 0) {
   /* 使用jdk动态代理 */
   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 {
   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的拦截器设计核心代码还是比较简单的,但是足够灵活。实际使用时注意,不做无意义的代理(Plugin.wrap)。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索java
mybatis inteceptor、mybatis 拦截器、mybatis 分页拦截器、mybatis 拦截器配置、mybatis自定义拦截器,以便于您获取更多的相关知识。

时间: 2024-12-28 18:53:56

java MyBatis拦截器Inteceptor详细介绍_java的相关文章

Mybatis拦截器的实现介绍_java

 MyBatis介绍 MyBatis本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis .它支持普通 SQL查询,存储过程和高级映射的优秀持久层框架.MyBatis 消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索.MyBatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的POJOs(Plain Old Java Objects,普通的

JAVA JNI函数的注册过程详细介绍_java

JAVA JNI函数的注册过程详细介绍 我们在java中调用Native code的时候,一般是通过JNI来实现的,我们只需要在java类中加载本地.so库文件,并声明native方法,然后在需要调用的地方调用即可,至于java中native方法的具体实现,全部交给了Native层.我们要在java中正确地调用到本地代码中对应函数的前提是什么呢?答案就是通过一定的机制建立java中native方法和本地代码中函数的一一对应关系,那么这种机制是什么呢?就是JNI函数的注册机制. JNI函数的注册有

java中MyBatis拦截器Inteceptor详解

本文主要分析MyBatis的插件机制,实际就是Java动态代理实现的责任链模式实现. 根据官方文档.Mybatis只允许拦截以下方法,这个决定写拦截器注解签名参数.  代码如下 复制代码 Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed) ParameterHandler (getParameterObject, setParameters) ResultSetH

Java输入输出流的使用详细介绍_java

1.什么是IO       Java中I/O操作主要是指使用Java进行输入,输出操作. Java所有的I/O机制都是基于数据流进行输入输出,这些数据流表示了字符或者字节数据的流动序列.Java的I/O流提供了读写数据的标准方法.任何Java中表示数据源的对象都会提供以数据流的方式读写它的数据的方法.         Java.io是大多数面向数据流的输入/输出类的主要软件包.此外,Java也对块传输提供支持,在核心库 java.nio中采用的便是块IO. 流IO的好处是简单易用,缺点是效率较低

Java中的Object类详细介绍_java

理论上Object类是所有类的父类,即直接或间接的继承java.lang.Object类.由于所有的类都继承在Object类,因此省略了extends Object关键字. 该类中主要有以下方法: toString(),getClass(),equals(),clone(),finalize(), 其中toString(),getClass(),equals是其中最重要的方法. 注意: Object类中的getClass(),notify(),notifyAll(),wait()等方法被定义为f

java selenium教程之selenium详细介绍_java

Selenium 是目前用的最广泛的Web UI 自动化测试框架. 本系列文章,将深入简出来讲解selenium 的用法 阅读目录 selenium 的命名 selenium 的意思是 硒   (有点QTP 杀手的意思) QTP mercury 是水银     硒可以对抗水银 QTP 目前的价格是  三个单机版 十万人民币左右, 越来越少的人用QTP了 什么是selenium 一套软件工具,用来支持不同的自动化测试方法 开源软件:可以根据需要来增加重构工具的某些功能 跨平台:linux , wi

java中的枚举类型详细介绍_java

枚举中有values方法用于按照枚举定义的顺序生成一个数组,可以用来历遍.我们自定义的枚举类都是继承自java.lang.Enum,拥有一下实例中的功能: 复制代码 代码如下: //: enumerated/EnumClass.java // Capabilities of the Enum class import static net.mindview.util.Print.*; enum Shrubbery { GROUND, CRAWLING, HANGING } public clas

Java中的阻塞队列详细介绍_java

Java中的阻塞队列 1. 什么是阻塞队列? 阻塞队列(BlockingQueue)是一个支持两个附加操作的队列.这两个附加的操作是: 在队列为空时,获取元素的线程会等待队列变为非空. 当队列满时,存储元素的线程会等待队列可用. 阻塞队列常用于生产者和消费者的场景,生产者是往队列里添加元素的线程,消费者是从队列里拿元素的线程.阻塞队列就是生产者存放元素的容器,而消费者也只从容器里拿元素. 2.Java里的阻塞队列 JDK中提供了七个阻塞队列: ArrayBlockingQueue :一个由数组结

java 中函数的参数传递详细介绍_java

 java中函数的参数传递 总结:   1.将对象(对象的引用)作为参数传递时传递的是引用(相当于指针).也就是说函数内对参数所做的修改会影响原来的对象.   2.当将基本类型或基本类型的包装集作为参数传递时,传递的是值.也就是说函数内对参数所做的修改不会影响原来的变量.   3.数组(数组引用))作为参数传递时传递的是引用(相当于指针).也就是说函数内对参数所做的修改会影响原来的数组.   4.String类型(引用)作为参数传递时传递的是引用,只是对String做出任何修改时有一个新的Str