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)最重要
public class MapperProxy<T> implements InvocationHandler, Serializable { private static final long serialVersionUID = -6424540398559729838L;
private final SqlSession sqlSession;
private final Class<T> mapperInterface;
private final Map<Method, MapperMethod> methodCache; public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
this.sqlSession = sqlSession;
this.mapperInterface = mapperInterface;
this.methodCache = methodCache;
} public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (Object.class.equals(method.getDeclaringClass())) {
try {
return method.invoke(this, args);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
} private MapperMethod cachedMapperMethod(Method method) {
MapperMethod mapperMethod = methodCache.get(method);
if (mapperMethod == null) {
mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
methodCache.put(method, mapperMethod);
}
return mapperMethod;
} }
根据几种操作类型做不同处理
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;
}
mybatis源码学习: 动态代理的应用(慢慢改)的更多相关文章
- MyBatis 源码分析——动态代理
MyBatis框架是如何去执行SQL语句?相信不只是你们,笔者也想要知道是如何进行的.相信有上一章的引导大家都知道SqlSession接口的作用.当然默认情况下还是使用DefaultSqlSessio ...
- mybatis源码学习:基于动态代理实现查询全过程
前文传送门: mybatis源码学习:从SqlSessionFactory到代理对象的生成 mybatis源码学习:一级缓存和二级缓存分析 下面这条语句,将会调用代理对象的方法,并执行查询过程,我们一 ...
- mybatis源码学习:插件定义+执行流程责任链
目录 一.自定义插件流程 二.测试插件 三.源码分析 1.inteceptor在Configuration中的注册 2.基于责任链的设计模式 3.基于动态代理的plugin 4.拦截方法的interc ...
- Mybatis源码学习第六天(核心流程分析)之Executor分析
今Executor这个类,Mybatis虽然表面是SqlSession做的增删改查,其实底层统一调用的是Executor这个接口 在这里贴一下Mybatis查询体系结构图 Executor组件分析 E ...
- mybatis源码学习(一) 原生mybatis源码学习
最近这一周,主要在学习mybatis相关的源码,所以记录一下吧,算是一点学习心得 个人觉得,mybatis的源码,大致可以分为两部分,一是原生的mybatis,二是和spring整合之后的mybati ...
- mybatis源码学习:一级缓存和二级缓存分析
目录 零.一级缓存和二级缓存的流程 一级缓存总结 二级缓存总结 一.缓存接口Cache及其实现类 二.cache标签解析源码 三.CacheKey缓存项的key 四.二级缓存TransactionCa ...
- Spring mybatis源码篇章-动态SQL节点源码深入
通过阅读源码对实现机制进行了解有利于陶冶情操,承接前文Spring mybatis源码篇章-动态SQL基础语法以及原理 前话 前文描述到通过mybatis默认的解析驱动类org.apache.ibat ...
- Mybatis源码解析 - mapper代理对象的生成,你有想过吗
前言 开心一刻 本人幼教老师,冬天戴帽子进教室,被小朋友看到,这时候,有个小家伙对我说:老师你的帽子太丑,赶紧摘了吧.我逗他:那你好好学习,以后给老师买个漂亮的?这孩子想都没想立刻回答:等我赚钱了,带 ...
- 【mybatis源码学习】mybtias知识点
Mybatis技术内幕系列博客,从原理和源码角度,介绍了其内部实现细节,无论是写的好与不好,我确实是用心写了,由于并不是介绍如何使用Mybatis的文章,所以,一些参数使用细节略掉了,我们的目标是介绍 ...
- Mybatis源码学习之整体架构(一)
简述 关于ORM的定义,我们引用了一下百度百科给出的定义,总体来说ORM就是提供给开发人员API,方便操作关系型数据库的,封装了对数据库操作的过程,同时提供对象与数据之间的映射功能,解放了开发人员对访 ...
随机推荐
- Netty4.x中文教程系列(三) Hello World !详解
Netty 中文教程 (二) Hello World !详解 上一篇文章,笔者提供了一个Hello World 的Netty示例. 时间过去了这么久,准备解释一下示例代码. 1.HelloServer ...
- Write operations are not allowed in read-only mode
使用Spring提供的Open Session In View而引起Write operations are not allowed in read-only mode (FlushMode.NEVE ...
- Data Base sqlServer DataReader与DataSet的区别
sqlServer DataReader与DataSet的区别 从以下这几个方面比较: 1.与数据库连接: DataReader:面向连接,只读,只进,只能向前读,读完数据就断开连接: DataS ...
- Win API 内存整理
记得我的笔记本上曾经安装了一款名为内存整理大师的软件,当时觉得挺好用而且挺NB的,就是导致开机启动有点慢. 当时我就在想,内存整理是怎么实现的?不过那是水平实在是不怎么样,估计连windows程序的消 ...
- The GPG keys listed not correct
The GPG keys listed for the "Extra Packages for Enterprise Linux 5 - x86_64" repository ar ...
- 二维码(2)二维码登录原理及Android客户端示例
1,原理 服务器: 数据库: 建立一个2维码登录的数据表,产生一个登录页时,插入一条记录X,X含将要登录的用户名字段(初始为空),2维码中的数据字段(唯一) 登录页面: 在产生的2维码中包含关键数据Y ...
- BZOJ 2754 喵星球上的点名(后缀数组)
题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2754 题意:给出n个字典串,m个询问串.输出每个询问串出现在多少个字典串中.最后输出每个 ...
- Android findBugs
1.Bug:DM_BOXED_PRIMITIVE_FOR_PARSING "Boxing/unboxing to parse a primitive", A boxed primi ...
- 《OD学hadoop》第一周0625
一.实用网站 1. linux内核版本 www.kernel.org 2. 查看网站服务器使用的系统 www.netcraft.com 二.推荐书籍 1. <Hadoop权威指南> 1- ...
- java socket编程基础
1. [代码]读操作Runable 1 package com.hrd.test.socket; import java.io.BufferedReader; import java.io.IOExc ...