mybatis源码学习: 动态代理的应用(慢慢改)

动态代理概述

在学spring的时候知道使用动态代理实现aop,入门的列子:需要计算所有方法的调用时间。可以每个方法开始和结束都获取当前时间咋办呢。类似这样:

long current=system.currenttimemillis();
调用原来的方法
long last=system.currenttimemillis();

如果每个方法都人工加入实在有点不爽,动态代理出场了。动态代理利用字节码技在原来对应的类的子节码进行重写,添加对应的逻辑。

主流的动态代理实现技术主流如下:JDK 和CGLIB,Javassist,ASM  参考这个

mybatis的应用

我们知道在mybatis中,我们只要编写mapper的接口和接口对应的mapper.xml ,利用下面方法就可以获取实例和调用方法。(代码来自mybatis3自带测试用例

BoundBlogMapper mapper = session.getMapper(BoundBlogMapper.class);

Blog b = mapper.selectBlogWithPostsUsingSubSelect(1);
assertEquals(1, b.getId());session.close();

这里面的mapper就是利用jdk中的动态代理方式获取的接口BoundBlogMapper的代理类的对象。具体方法自己看。很容易跟踪。jdk动态代理最重要的就是实现

InvocationHandler接口的处理累。最重调用如下。invoke方法中mapperMethod.execute(sqlSession, args)最重要
 1 public class MapperProxy<T> implements InvocationHandler, Serializable {
 2
 3   private static final long serialVersionUID = -6424540398559729838L;
 4   private final SqlSession sqlSession;
 5   private final Class<T> mapperInterface;
 6   private final Map<Method, MapperMethod> methodCache;
 7
 8   public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
 9     this.sqlSession = sqlSession;
10     this.mapperInterface = mapperInterface;
11     this.methodCache = methodCache;
12   }
13
14   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
15     if (Object.class.equals(method.getDeclaringClass())) {
16       try {
17         return method.invoke(this, args);
18       } catch (Throwable t) {
19         throw ExceptionUtil.unwrapThrowable(t);
20       }
21     }
22     final MapperMethod mapperMethod = cachedMapperMethod(method);
23     return mapperMethod.execute(sqlSession, args);
24   }
25
26   private MapperMethod cachedMapperMethod(Method method) {
27     MapperMethod mapperMethod = methodCache.get(method);
28     if (mapperMethod == null) {
29       mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
30       methodCache.put(method, mapperMethod);
31     }
32     return mapperMethod;
33   }
34
35 }

根据几种操作类型做不同处理

public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    if (SqlCommandType.INSERT == command.getType()) {
      Object param = method.convertArgsToSqlCommandParam(args);
      result = rowCountResult(sqlSession.insert(command.getName(), param));
    } else if (SqlCommandType.UPDATE == command.getType()) {
      Object param = method.convertArgsToSqlCommandParam(args);
      result = rowCountResult(sqlSession.update(command.getName(), param));
    } else if (SqlCommandType.DELETE == command.getType()) {
      Object param = method.convertArgsToSqlCommandParam(args);
      result = rowCountResult(sqlSession.delete(command.getName(), param));
    } else if (SqlCommandType.SELECT == command.getType()) {
      if (method.returnsVoid() && method.hasResultHandler()) {
        executeWithResultHandler(sqlSession, args);
        result = null;
      } else if (method.returnsMany()) {
        result = executeForMany(sqlSession, args);
      } else if (method.returnsMap()) {
        result = executeForMap(sqlSession, args);
      } else {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = sqlSession.selectOne(command.getName(), param);
      }
    } else if (SqlCommandType.FLUSH == command.getType()) {
        result = sqlSession.flushStatements();
    } else {
      throw new BindingException("Unknown execution method for: " + command.getName());
    }
    if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
      throw new BindingException("Mapper method ‘" + command.getName()
          + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
    }
    return result;
  }

 

时间: 2024-10-13 15:59:15

mybatis源码学习: 动态代理的应用(慢慢改)的相关文章

MyBatis 源码分析——动态代理

MyBatis框架是如何去执行SQL语句?相信不只是你们,笔者也想要知道是如何进行的.相信有上一章的引导大家都知道SqlSession接口的作用.当然默认情况下还是使用DefaultSqlSession类.关于SqlSession接口的用法有很多种.笔者还是比较喜欢用getMapper方法.对于getMapper方法的实现方式.笔者不能下一个定论.笔者只是想表示一下自己的理解而以--动态代理. 笔者把关于getMapper方法的实现方式理解为动态代理.事实上笔者还想说他可以是一个AOP思想的实现

Mybatis源码学习记录

一.对源码先上一个结构图: 源代码主要在org.apache.ibatis目录下,18个包,其中在应用中主要的包有:builder.session.cache.type.transaction.datasource.jdbc.mapping,提供支撑服务的包有annotation.binding.io.logging.plugin.reflection.scripting.exception.executor.parsing 二.从使用入手 MyBatis使用的三板斧是SqlSessionFac

mybatis专题(三)-----mybatis源码学习

源码分析概述 源码包分析 下载地址 MyBatis 源码下载地址:https://github.com/mybatis/mybatis-3 导入过程 1. 下载MyBatis的源码 2. 检查maven的版本,必须是3.25以上,建议使用maven的最新版本 3. mybatis的工程是maven工程,在开发工具中导入,工程必须使用jdk1.8以上版本: 4. 把mybatis源码的pom文件中true,全部改为false,或者直接删除这行: 5. 在工程目录下执行 mvn clean inst

MyBatis 源码分析——动态SQL语句

有几年开发经验的程序员应该都有暗骂过原生的SQL语句吧.因为他们不能一句就搞定一个业务,往往还要通过代码来拼接相关的SQL语句.相信大家会理解SQL里面的永真(1=1),永假(1=2)的意义吧.所以mybatis动态SQL功能在笔者看来是最引吸人的.为了更好的区别XML映射文件上的SQL语句.mybatis把SQL语句分为四类.那么这个笔者已经在前面的章节里面讲过了.但是我们在开发过程中常常用到的也就俩种:静态和动态. 关于静态和动态的定义,笔者是这样子理解的--静态SQL语句显示就是里面没有相

mybatis源码学习: 编译的方法

mybatis3用了一段时间,抽出时间来研究一下.具体用法参考官方文档就行,源码在这里.mybatis相对而言,规模较小,可以从中学习如何编写高质量的java项目. mybatis3使用maven管理.方法很简单. 1,mybatis3项目依赖父项目,所以先clone这个项目,然后mvn install 就可以了.就会安装到本地仓库. 2.再mvn install  mybatis-3对应的项目就成功了

Mybatis 源码学习系列

前言 很久以前,我们学习了Java,从一个控制台的 Hello world .开始,我们进入了面向对象的世界. 然后由学习了SQL语言,可以写出SQL语句来将尘封在硬盘之下的数据库数据,展现出来. 后来我们使用JDBC 来操作数据库,进行各种增删改查.然而,我们对于原生的JDBC并不满意,写起来很不爽-- 于是,我们使用了Mybatis,写了一个又一个的mapper,无论需求怎么变动,无论情况怎么复杂多变.对于我们来说只是增加mapper,修改xml中的sql就好了. 从此,一切似乎很简单,水到

【mybatis源码学习】与spring整合Mapper接口执行原理

一.重要的接口 org.mybatis.spring.mapper.MapperFactoryBean MapperScannerConfigurer会向spring中注册该bean,一个mapper接口注册一个 该类是生产MapperProxy对象 org.apache.ibatis.binding.MapperProxy mapper接口的代理类 org.mybatis.spring.SqlSessionInterceptor sqlSession的动态代理类 org.mybatis.spr

【mybatis源码学习】mybatis的参数处理

一.mybatis的参数处理以及参数取值 1.单个参数 mybatis不做任何处理 取值方式: ? #{参数名/任意名} <!-- Employee getEmpById(Integer id); --> <select id="getEmpById" resultType="com.mxc.bean.Employee"> select * from employee where id=#{id} </select> 2.多个参数

【mybatis源码学习】调试mybatis的第一个程序

[一].基础知识准备 mybatis-config.xml配置文件的结构 MyBatis配置文件中大标签configuration下子标签包括: configuration |--- properties |--- settings |--- typeAliases |--- typeHandlers |--- objectFactory |--- plugins |--- environments |--- |--- environment |--- |--- |--- transaction