mybatis源码阅读(四):mapper(dao)实例化

转载自   mybatis源码阅读(四):mapper(dao)实例化

在开始分析之前,先来了解一下这个模块中的核心组件之间的关系,如图:

1.MapperRegistry&MapperProxyFactory

MapperRegistry是Mapper接口及其对应的代理对象工程的注册中心,Configuration是Mybatis全局性的配置对象,在初始化的过程中,所有配置信息会被解析成相应的对象并记录到Configuration对象中,这在之前也详细介绍了。Configuration.mapperRegistry字段记录当前使用的MapperRegistry对象,

public class MapperRegistry {// 全局唯一的配置对象,其中包含了所有的配置信息private final Configuration config;// 记录Mapper接口与对应MapperProxyFactory之间的关系private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();
}private void bindMapperForNamespace() {String namespace = builderAssistant.getCurrentNamespace();if (namespace != null) {Class<?> boundType = null;try {boundType = Resources.classForName(namespace);} catch (ClassNotFoundException e) {//ignore, bound type is not required}if (boundType != null) {if (!configuration.hasMapper(boundType)) {// Spring may not know the real resource name so we set a flag// to prevent loading again this resource from the mapper interface// look at MapperAnnotationBuilder#loadXmlResourceconfiguration.addLoadedResource("namespace:" + namespace);configuration.addMapper(boundType);}}}
}
public <T> void addMapper(Class<T> type) {mapperRegistry.addMapper(type);
}
public <T> void addMapper(Class<T> type) {if (type.isInterface()) {//是否为接口if (hasMapper(type)) {//是否已经加载过throw new BindingException("Type " + type + " is already known to the MapperRegistry.");}boolean loadCompleted = false;try {knownMappers.put(type, new MapperProxyFactory<T>(type));// 注解处理MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);parser.parse();loadCompleted = true;} finally {if (!loadCompleted) {knownMappers.remove(type);}}}
}

在需要执行SQL语句时,会先获取mapper借口的代理对象,例如:

@Test
public void findUserById() {SqlSession sqlSession = getSessionFactory().openSession();UserDao userMapper = sqlSession.getMapper(UserDao.class);User user = userMapper.findUserById(1);Assert.assertNotNull("没找到数据", user);
}

DefaultSqlSession类中方法如下,实际上是通过JDK动态代理生成的代理对象

public <T> T getMapper(Class<T> type) {return this.configuration.getMapper(type, this);
}

Configuration类方法如下:

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {return mapperRegistry.getMapper(type, sqlSession);
}

MapperRegistry类中方法如下:

@SuppressWarnings("unchecked")
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {//查找指定type对象的MapperProxyFactory对象final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);if (mapperProxyFactory == null) {//如果为空抛出异常throw new BindingException("Type " + type + " is not known to the MapperRegistry.");}try {// 创建实现了type接口的代理对象return mapperProxyFactory.newInstance(sqlSession);} catch (Exception e) {throw new BindingException("Error getting mapper instance. Cause: " + e, e);}
}

MapperProxyFactory主要负责创建代理对象

@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}public T newInstance(SqlSession sqlSession) {final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);return newInstance(mapperProxy);
}

2.MapperProxy

MapperProxy实现了InvocationHandler接口,对动态代理的可以先去了解这篇文章https://my.oschina.net/u/3737136/blog/1786175

public class MapperProxy<T> implements InvocationHandler, Serializable {private static final long serialVersionUID = -6424540398559729838L;// 记录关联的SQLSession对象private final SqlSession sqlSession;// mapper接口对应的class对象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;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {// 如果目标方法是Object类继承来的,直接调用目标方法if (Object.class.equals(method.getDeclaringClass())) {return method.invoke(this, args);} else if (isDefaultMethod(method)) {return invokeDefaultMethod(proxy, method, args);}} catch (Throwable t) {throw ExceptionUtil.unwrapThrowable(t);}// 从缓存中获取MapperMethod 对象,如果没有就创建新的并添加final MapperMethod mapperMethod = cachedMapperMethod(method);// 执行sql 语句return mapperMethod.execute(sqlSession, args);}}

3.MapperMethod

MapperMethod中封装了Mapper接口中对应方法的信息,以及对应SQL语句的信息,

public class MapperMethod {// 记录SQL语句的名称和类型private final SqlCommand command;// mapper接口中对应方法的相关信息private final MethodSignature method;public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {this.command = new SqlCommand(config, mapperInterface, method);this.method = new MethodSignature(config, mapperInterface, method);}public Object execute(SqlSession sqlSession, Object[] args) {Object result;switch (command.getType()) {case INSERT: {Object param = method.convertArgsToSqlCommandParam(args);result = rowCountResult(sqlSession.insert(command.getName(), param));break;}case UPDATE: {Object param = method.convertArgsToSqlCommandParam(args);result = rowCountResult(sqlSession.update(command.getName(), param));break;}case DELETE: {Object param = method.convertArgsToSqlCommandParam(args);result = rowCountResult(sqlSession.delete(command.getName(), param));break;}case SELECT:if (method.returnsVoid() && method.hasResultHandler()) {// 处理返回值为void ,ResultSet 通过ResultHand处理的方法executeWithResultHandler(sqlSession, args);result = null;} else if (method.returnsMany()) {// 处理返回值为集合或者数组的方法result = executeForMany(sqlSession, args);} else if (method.returnsMap()) {// 处理返回值为map的方法result = executeForMap(sqlSession, args);} else if (method.returnsCursor()) {// 处理返回值为cursor的方法result = executeForCursor(sqlSession, args);} else {// 处理返回值为单一对象的方法Object param = method.convertArgsToSqlCommandParam(args);result = sqlSession.selectOne(command.getName(), param);}break;case FLUSH:result = sqlSession.flushStatements();break;default: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;}
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/322749.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

自定义路由匹配和生成

前言 前两篇文章主要总结了CMS系统两个技术点在ASP.NET Core中的应用&#xff1a; 《ASP.NET Core 中的SEO优化&#xff08;1&#xff09;&#xff1a;中间件实现服务端静态化缓存》 《ASP.NET Core 中的SEO优化&#xff08;2&#xff09;&#xff1a;中间件中渲染Razor视图》…

如何封装并发布一个属于自己的ui组件库

以前就一直有个想法自己能不能封装一个类似于elementui一样的组件库&#xff0c;然后发布到npm上去&#xff0c;毕竟前端说白了&#xff0c;将组件v上去&#xff0c;然后进行数据交互。借助这次端午&#xff0c;终于有机会&#xff0c;尝试自己去封装发布组件库了 我这里了只做…

听云支持.NET Core的应用性能监控

随着微软于2017年8月正式发布.NET Core 2.0&#xff0c; .NET Core 社区开始活跃&#xff0c;众多.NET开发者开始向跨平台转变。 听云于2017年11月推出了.NET Core应用监控工具&#xff0c;和听云其他语言的监控工具一样&#xff0c;.NET Core应用监控工具具有以下特征&#xf…

mybatis源码阅读(五) ---执行器Executor

转载自 mybatis源码阅读(五) ---执行器Executor 1. Executor接口设计与类结构图 public interface Executor {ResultHandler NO_RESULT_HANDLER null;// 执行update&#xff0c;delete&#xff0c;insert三种类型的sql语句int update(MappedStatement ms, Object parameter…

[52ABP实战系列] .NET CORE实战入门第三章更新了

早安 各位道友好&#xff0c;.NET CORE入门视频的第三章也算录制完毕了。欢迎大家上传课网进行学习。 更新速度 大家也知道最近的社会新闻比较多。频繁发生404、关键字打不出来&#xff0c;我个人也在关注这些事件。导致精力分散&#xff0c;没有做到稳定更新&#xff0c;现在呢…

如何安装nuxt

因为vue是单页面应用&#xff0c;所以不被Seo&#xff0c;如百度和Google抓取到&#xff0c;在Vue中如果想要爬虫爬到就必须使用nuxt 那么如何安装使用呢&#xff1f; yarn create nuxt-app <project-name> cd <project-name> yarn build yarn start必须先build&a…

mybatis源码阅读(六) ---StatementHandler了解一下

转载自 mybatis源码阅读(六) ---StatementHandler了解一下 StatementHandler类结构图与接口设计 BaseStatementHandler&#xff1a;一个抽象类&#xff0c;只是实现了一些不涉及具体操作的方法 RoutingStatementHandler&#xff1a;类似路由器&#xff0c;根据配置文件来路由…

基于OIDC(OpenID Connect)的SSO(纯JS客户端)

在上一篇基于OIDC的SSO的中涉及到了4个Web站点&#xff1a; oidc-server.dev&#xff1a;利用oidc实现的统一认证和授权中心&#xff0c;SSO站点。 oidc-client-hybrid.dev&#xff1a;oidc的一个客户端&#xff0c;采用hybrid模式。 oidc-client-implicit.dev&#xff1a;od…

IIS中的 Asp.Net Core 和 dotnet watch

在基于传统的.NET Framework的Asp.Net Mvc的时候&#xff0c;本地开发环境中可以在IIS中建立一个站点&#xff0c;可以直接把站点的目录指向asp.net mvc的项目的根目录。然后build一下就可以在浏览器里面刷新到最新的修改了&#xff0c;也可以附加到w3wp的进程进行调试。但是在…

foreach方法使用

用法 foreach方法主要是针对数组而言的&#xff0c;对数组中的每个元素可以执行一次方法 var array [a, b, c, e]; array.forEach((a)> {console.log(a); });属性 foreach方法主要有三个参数&#xff0c;分别是数组内容、数组索引、整个数组 var array [a, b, c, e]; arra…

.NET Core 控制台程序读 appsettings.json 、注依赖、配日志、设 IOptions

.NET Core 控制台程序没有 ASP.NET Core 的 IWebHostBuilder 与 Startup.cs &#xff0c;那要读 appsettings.json、注依赖、配日志、设 IOptions 该怎么办呢&#xff1f;因为这些操作与 ASP.NET Core 无依赖&#xff0c;所以可以自己动手&#xff0c;轻松搞定。 1、读 appsett…

Object.keys方法拿到对象的key值

项目中的高级搜索选项用到了Object.keys方法&#xff0c; 那么它是用来干嘛的呢&#xff1a;删除某个子对象里的数据 var anObj { aaa: kejin,bbb: shenxian,ccc: yuanshan };let params {...anObj,ddd: luanwu } console.log(params) console.log(Object.keys(anObj)); // …

jsdiff 比较文本内容差异

翻译自 jsdiff JavaScript文本内容差异实现。 基于"An O(ND) Difference Algorithm and its Variations" (Myers, 1986) 中提出的算法 。 安装 npm install diff --save API Diff.diffChars(oldStr, newStr[, options]) -区分两个文本块&#xff0c;逐字符比较。…

Net Core下多种ORM框架特性及性能对比

在.NET Framework下有许多ORM框架&#xff0c;最著名的无外乎是Entity Framework&#xff0c;它拥有悠久的历史以及便捷的语法&#xff0c;在占有率上一路领先。但随着Dapper的出现&#xff0c;它的地位受到了威胁&#xff0c;本文对比了在.NET Core下 两种框架的表现以及与原生…

从ThoughtWorks 2017技术雷达看微软技术

ThoughtWorks在每年都会出品两期技术雷达&#xff0c;这是一份关于技术趋势的报告&#xff0c;它比起一些我们能在市面上见到的其他各种技术行情和预测报告&#xff0c;更加具体&#xff0c;更具可操作性&#xff0c;因为它不仅涉及到新技术大趋势&#xff0c;比如云平台和大数…

Spark入门(一)单主standalone安装

一、集群安装条件前置 实验spark安装在【Hadoop入门&#xff08;二&#xff09;集群安装】机器上&#xff0c; 已完成安装jdk,hadoop和ssh、网络等配置环境等。 spark所依赖的虚拟机和操作系统配置 环境&#xff1a;ubuntu14 spark-2.4.4-bin-hadoop2.6jdk1.8ssh 虚拟机&a…

AutoMapper在asp.netcore中的使用

automapper 是.net 项目中针对模型之间转换映射的一个很好用的工具&#xff0c;不仅提高了开发的效率还使代码更加简洁&#xff0c;当然也是开源的&#xff0c;https://github.com/AutoMapper&#xff0c;这不多做介绍&#xff0c;详细看&#xff0c;官网下面是介绍它在 .net c…

Hadoop生态Zookeeper安装

一、安装条件前置 实验zookeeper安装在【Hadoop入门&#xff08;二&#xff09;集群安装】机器上&#xff0c;已完成安装jdk,hadoop和ssh配置环境等。 zookeeper所依赖的虚拟机和操作系统配置 环境&#xff1a;ubuntu14 apache-zookeeper-3.5.6-bin.tar jdk1.8ssh 虚拟机…

Hangfire在ASP.NET CORE中的简单实现

hangfire是执行后台任务的利器&#xff0c;具体请看官网介绍&#xff1a;https://www.hangfire.io/ 新建一个asp.net core mvc 项目 引入nuget包 Hangfire.AspNetCore hangfire的任务需要数据库持久化&#xff0c;我们在Startup类中修改ConfigureServices 然后在Configure方法中…

Spark入门(二)多主standalone安装

一、集群安装条件前置 实验spark安装在【Hadoop生态Zookeeper安装】机器上&#xff0c; 已完成安装zookeeper、jdk、hadoop和ssh、网络等配置环境等。 spark所依赖的虚拟机和操作系统配置 环境&#xff1a;ubuntu14 spark-2.4.4-bin-hadoop2.6 apache-zookeeper-3.5.6 jd…