`
projecttian
  • 浏览: 33507 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

mybatis源码解析之拦截器

阅读更多

拦截器核心类:

先来看看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(接口类型)

 

 

分享到:
评论
1 楼 secondriver 2013-11-26  
" target="_blank">" />" target="_blank">" wmode="" quality="high" menu="false" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" width="200" height="200">

相关推荐

    mybatis源码分析思维导图.rar

    MyBatis是一款流行的Java...总的来说,MyBatis源码分析思维导图会涵盖MyBatis的各个关键组件、工作流程、特性以及扩展机制。通过深入学习和理解这些内容,开发者能够更好地利用MyBatis进行数据库操作,并优化其性能。

    mybatis源码分析视频

    通过本套"mybatis源码分析视频",学习者可以跟随视频逐步解析MyBatis的源码,了解这些核心组件如何协同工作,以及如何根据实际需求进行定制和优化。同时,文档可能包含详细的步骤说明、示例代码和关键知识点解析,...

    MyBatis源码详解学习.zip

    通过实现Interceptor接口并注册,开发者可以自定义拦截器,对Executor、StatementHandler、ParameterHandler和ResultSetHandler的行为进行增强。 总的来说,《MyBatis源码详解学习》这份资料涵盖了MyBatis框架的...

    CXF3.1.16 +Spring4 +MyBatis + Maven自定义拦截器 WebService实例源码下载

    "CXF3.1.16 +Spring4 +MyBatis + Maven自定义拦截器 WebService实例源码下载" 这个标题揭示了该项目的核心技术栈,包括: 1. CXF 3.1.16:这是一个开源的服务框架,用于构建和开发服务,支持SOAP和RESTful Web服务...

    mybatis分页拦截器

    MyBatis 分页拦截器是一种优化数据库查询性能的工具,它允许我们在不修改原有业务代码的情况下,实现对数据库查询结果的分页处理。在大型Web应用中,分页功能是必不可少的,因为它可以帮助用户更有效地浏览和管理...

    mybatis源码和官方的中文文档

    2. **MyBatis源码解析**: `mybatis-2.3.5-sources.jar`包含了MyBatis的源代码,这对于我们理解框架内部工作流程极其有价值。例如,你可以看到`SqlSession`、`SqlSessionFactory`和`Mapper`接口的实现,以及如何...

    mybatis源码分析

    11. MyBatis插件:通过拦截器机制,用户可以自定义插件来扩展MyBatis的功能,如日志、性能分析等。 在分析MyBatis源码时,开发者通常会关注以下几个方面: 1. 源码结构:了解MyBatis的模块划分,如sql解析、执行、...

    MyBatis源码demo

    《MyBatis源码分析与实战应用》 在IT行业中,MyBatis作为一个轻量级的持久层框架,因其灵活性和高效性而被广泛应用。它将SQL语句与Java代码相结合,提供了比传统JDBC更方便的数据操作方式。本文将深入探讨MyBatis的...

    MyBatis源码包

    标题中的"MyBatis源码包"指的是包含了MyBatis框架的源代码文件,这对于开发者来说是一份宝贵的学习资源。通过阅读源码,开发者可以深入理解MyBatis的工作原理,学习如何设计和实现一个高效的ORM框架,以及如何处理...

    mybatis 3.2.7 源码

    10. **插件支持**:MyBatis允许用户自定义插件,拦截Executor、StatementHandler、ParameterHandler和ResultSetHandler的关键方法,进行增强或监控。 通过研究MyBatis 3.2.7的源码,开发者可以理解其执行流程,学习...

    mybatis源码

    在深入MyBatis源码之前,我们需要了解一些基础概念。MyBatis的核心组件包括SqlSessionFactory、SqlSession和Executor。SqlSessionFactory是创建SqlSession的工厂,SqlSession是与数据库交互的主要接口,而Executor则...

    Mybatis学习源码的实例代码

    此外,学习Mybatis源码还能帮助你理解如何自定义插件,比如Interceptor拦截器,它可以插入到Executor、StatementHandler、ParameterHandler、ResultSetHandler的执行链中,实现自定义功能。 总的来说,这个实例代码...

    mybatis拦截器

    ### MyBatis拦截器原理与应用 #### 一、MyBatis拦截器概述 MyBatis作为一款优秀的持久层框架,提供了丰富的扩展机制,其中一项重要特性便是插件(plugin)功能,实际上指的是拦截器功能。通过拦截器,开发人员可以在...

    Mybatis系列教程Mybatis源码剖析共15页.pd

    【标题】"Mybatis系列教程Mybatis源码剖析共15页.pdf" 是一份详细的Mybatis框架源码解析教程,涵盖了Mybatis的核心概念和技术细节。这份教程深入浅出地介绍了Mybatis如何工作,以及其背后的代码实现,对于理解...

    MyBatis 分页源码简单

    在 PageHelper 插件中,主要通过拦截器机制实现分页功能。当执行 SQL 查询时,`PageInterceptor` 会拦截到这个过程,然后根据分页参数(如 `@Page` 注解)动态生成分页 SQL。在 MySQL 中,这通常意味着在原始 SQL ...

    mybatis实战源码

    - MyBatis提供了一个强大的插件机制,用户可以自定义拦截器实现SQL执行前后的增强功能,如日志、性能分析等。 7. MyBatis的Spring整合 - MyBatis与Spring整合后,可以使用Spring的事务管理,简化了事务控制和依赖...

    mybatis-3.0.4源码

    MyBatis允许开发者自定义拦截器,通过Interceptor接口实现,可以拦截SQLSession的某些操作,例如添加日志、性能监控等。 七、事务管理 MyBatis支持手动和自动两种事务管理方式。手动模式下,开发者需在代码中显式...

    互联网轻量级SSM框架解密:Spring、Spring MVC、MyBatis源码深度剖析 .rar

    SSM框架,全称为Spring、Spring MVC和MyBatis,是Java开发中广泛使用的轻量级Web...提供的"互联网轻量级SSM框架解密:Spring、Spring MVC、MyBatis源码深度剖析.pdf"文档,无疑是一份宝贵的参考资料,值得深入研究。

    mybatis源码级课件DTD文件jar包xml文件最全最新

    `MyBatis_09_source`可能涉及到了MyBatis源码的深度解析,有助于开发者理解MyBatis内部的工作流程,如SQL映射的解析、参数绑定、结果映射等核心过程。 `mybatis.dtd`文件是MyBatis的文档类型定义(DTD),它是XML...

    mybatis项目源码

    7. **插件机制**:了解MyBatis的拦截器插件,如何自定义插件实现日志、性能统计等功能。 8. **缓存的实现**:查看MyBatis如何实现本地缓存和二级缓存,以及如何配置缓存策略。 通过分析这些源码,初学者不仅可以...

Global site tag (gtag.js) - Google Analytics