Spring整合MyBatis(四)MapperFactoryBean 的创建
摘要: 本文结合《Spring源码深度解析》来分析Spring 5.0.6版本的源代码。若有描述错误之处,欢迎指正。
目录
一、MapperFactoryBean的初始化
二、获取 MapperFactoryBean 的实例
为了使用MyBatis功能,示例中的Spring配置文件提供了两个bean,除了之前分析的 SqlSessionFactoryBean 类型的 bean 以外,还有一个是 MapperFactoryBean 类型的 bean。
结合两个测试用例综合分析,对于单独使用MyBatis的时候调用数据库接口的方式是:
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
而在这一过程中,其实是MyBatis在获取映射的过程中根据配置信息为UserMapper类型动态创建了代理类。而对于Spring的创建方式:
UserMapper userMapper = (UserMapper) context.getBean("userMapper");
Spring中获取的名为userMapper的bean,其实是与单独使用MyBatis完成了—样的功能,那么我们可以推断,在bean的创建过程中一定是使用了MyBatis中的原生方法sqlSession.getMapper(UserMapper.class)进行了再一次封装。结合配置文件,我们把分析目标转向org.mybatis.spring.mapper.MapperFactoryBean,初步推测其中的逻辑应该在此类中实现。同样,还是首先查看的类层次结构图MapperFactoryBean,如下图所示。

同样,在实现的接口中发现了我们感兴趣的两个接口InitializingBean与FactoryBean。我们的分析还是从bean的初始化开始。
一、MapperFactoryBean的初始化
因为实现了InitializingBean接口,Spring会保证在bean初始化时首先调用afterPropertiesSet方法来完成其初始化逻辑。追踪父类,发现afterPropertiesSet方法是在DaoSupport类中实现,代码如下:
@Override
public final void afterPropertiesSet() throws IllegalArgumentException, BeanInitializationException {
// Let abstract subclasses check their configuration.
checkDaoConfig(); // Let concrete implementations initialize themselves.
try {
initDao();
}
catch (Exception ex) {
throw new BeanInitializationException("Initialization of DAO failed", ex);
}
}
但从函数名称来看我们大体推测,MapperFactoryBean的初始化包括对DAO配置的验证以及对DAO的初始工作,其中initDao()方法是模板方法,设计为留给子类做进一步逻辑处理。而checkDaoConfig()才是我们分析的重点。
@Override
protected void checkDaoConfig() {
super.checkDaoConfig(); notNull(this.mapperInterface, "Property 'mapperInterface' is required"); Configuration configuration = getSqlSession().getConfiguration();
if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
try {
configuration.addMapper(this.mapperInterface);
} catch (Exception e) {
logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", e);
throw new IllegalArgumentException(e);
} finally {
ErrorContext.instance().reset();
}
}
}
super.checkDaoConfig()在SqlSessionDaoSupport类中实现,代码如下:
@Override
protected void checkDaoConfig() {
notNull(this.sqlSessionTemplate, "Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required");
}
结合代码我们了解到对于DAO配置的验证,Spring做了以下几个方面的工作。
- 父类中对于sqlSession不为空的验证。
sqlSession作为根据接口创建映射器代理的接触类一定不可以为空,而sqlSession的初始化工作是在设定其sqlSessionFactory属性时完成的。
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
if (this.sqlSessionTemplate == null || sqlSessionFactory != this.sqlSessionTemplate.getSqlSessionFactory()) {
this.sqlSessionTemplate = createSqlSessionTemplate(sqlSessionFactory);
}
}
也就是说,对于下面的配置如果忽略了对于sqlSessionFactoiy属性的设置,那么在此时就会被检测出来。
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="org.cellphone.uc.repo.mapper.UserMapper"/>
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
- 映射接口的验证。
接口是映射器的基础,sqlSession会根据接口动态创建相应的代理类,所以接口必不可少。
- 映射文件存在性验证。
对于函数前半部分的验证我们都很容易理解,无非是对配置文件中的属性是否存在做验证,但是后面部分是完成了什么方面的验证呢?如果读者读过MyBatis源码,你就会知道,在MyBatis实现过程中并没有手动调用configuration.addMapper方法,而是在映射文件读取过程中一旦解析到如<mapper namespace="org.cellphone.uc.repo.mapper.UserMapper">,便会自动进行类型映射的注册。那么,Spring中为什么会把这个功能单独拿出来放在验证里呢?这是不是多此一举呢?
在上面的函数中,configuration.addMapper(this.mapperInterface)其实就是将 UserMapper 注册到映射类型中,如果你可以保证这个接口一定存在对应的映射文件,那么其实这个验证并没有必要。但是,由于这个是我们自行决定的配置,无法保证这里配罝的接口一定存在对应的映射文件,所以这里非常有必要进行验证。在执行此代码的时候,MyBatis会检査嵌人的映射接口是否存在对应的映射文件,如果没有回抛出异常,Spring正是在用这种方式来完成接口对应的映射文件存在性验证。
二、获取 MapperFactoryBean 的实例
由于MapperFactoryBean实现了FactoryBean接口,所以当通过getBean方法获取对应实例的时候其实是获取该类的getObject()函数返回的实例。
@Override
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}
这段代码正是我们在提供MyBatis独立使用的时候的一个代码调用。Spring通过 FactoryBean 进行了封装。
Spring整合MyBatis(四)MapperFactoryBean 的创建的更多相关文章
- spring基础:什么是框架,框架优势,spring优势,耦合内聚,什么是Ioc,IOC配置,set注入,第三方资源配置,综合案例spring整合mybatis实现
知识点梳理 课堂讲义 1)Spring简介 1.1)什么是框架 源自于建筑学,隶属土木工程,后发展到软件工程领域 软件工程中框架的特点: 经过验证 具有一定功能 半成品 1.2)框架的优势 提高开发效 ...
- Java开发学习(十四)----Spring整合Mybatis及Junit
一.Spring整合Mybatis思路分析 1.1 环境准备 步骤1:准备数据库表 Mybatis是来操作数据库表,所以先创建一个数据库及表 create database spring_db cha ...
- Spring整合MyBatis(三)sqlSessionFactory创建
摘要: 本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 目录 一.SqlSessionFactoryBean的初始化 二.获取 ...
- Mybatis学习(六)————— Spring整合mybatis
一.Spring整合mybatis思路 非常简单,这里先回顾一下mybatis最基础的根基, mybatis,有两个配置文件 全局配置文件SqlMapConfig.xml(配置数据源,全局变量,加载映 ...
- Mybatis(六) Spring整合mybatis
心莫浮躁~踏踏实实走,一步一个脚印,就算不学习,玩,能干嘛呢?人生就是那样,要找点有意思,打发时间的事情来做,而钻研技术,动脑动手的过程,还是比其他工作更有意思些~ so,努力啥的都是强迫自己做自以为 ...
- Spring学习总结(六)——Spring整合MyBatis完整示例
为了梳理前面学习的内容<Spring整合MyBatis(Maven+MySQL)一>与<Spring整合MyBatis(Maven+MySQL)二>,做一个完整的示例完成一个简 ...
- Spring学习总结(五)——Spring整合MyBatis(Maven+MySQL)二
接着上一篇博客<Spring整合MyBatis(Maven+MySQL)一>继续. Spring的开放性和扩张性在J2EE应用领域得到了充分的证明,与其他优秀框架无缝的集成是Spring最 ...
- 深入源码理解Spring整合MyBatis原理
写在前面 聊一聊MyBatis的核心概念.Spring相关的核心内容,主要结合源码理解Spring是如何整合MyBatis的.(结合右侧目录了解吧) MyBatis相关核心概念粗略回顾 SqlSess ...
- 分析下为什么spring 整合mybatis后为啥用不上session缓存
因为一直用spring整合了mybatis,所以很少用到mybatis的session缓存. 习惯是本地缓存自己用map写或者引入第三方的本地缓存框架ehcache,Guava 所以提出来纠结下 实验 ...
- 2017年2月16日 分析下为什么spring 整合mybatis后为啥用不上session缓存
因为一直用spring整合了mybatis,所以很少用到mybatis的session缓存. 习惯是本地缓存自己用map写或者引入第三方的本地缓存框架ehcache,Guava 所以提出来纠结下 实验 ...
随机推荐
- node、npm的安装和环境变量的配置
在使用node过程中踩过好几次坑,这次记录下来,以防以后在掉下去. 用npm安装nrm模块后,输入nrm 提示 “nrm”不是内部或外部命令,也不是可运行的程序.我就奇怪了,安装成功了,怎么还提示不是 ...
- HackerRank Special Substrings 回文树+后缀自动机+set
传送门 既然要求对每个前缀都求出答案,不难想到应该用回文树求出所有本质不同的回文子串. 然后考虑如何对这些回文子串的前缀进行去重. 结论:答案等于所有本质不同的回文子串长之和减去字典序相邻的回文子串的 ...
- 洛谷P4783 【模板】矩阵求逆(高斯消元)
题意 题目链接 Sol 首先在原矩阵的右侧放一个单位矩阵 对左侧的矩阵高斯消元 右侧的矩阵即为逆矩阵 // luogu-judger-enable-o2 #include<bits/stdc++ ...
- 转:Jquery如何获取某个元素前(后)的文本内容?
原文:[解决]Jquery如何获取某个元素前(后)的文本内容? <span> text here... <a id="target_element">百万创 ...
- 浏览器根对象document之数值和布尔属性
1.1 节点类型 ELEMENT_NODE 1 一个 元素 节点,例如 <p> 和 <div>. TEXT_NODE 3 Element 或者 Attr 中实际的文字 PROC ...
- 【webpack】从零开始学webpack
背景:目前公司的项目全是用vue写的,建项目的话使用的是用vue-cli直接配置好的webpack,进行打包.现在我就是想实现自己写一个类似vue-cli的架子 一.安装全局依赖 npm instal ...
- Reducing and Profiling GPU Memory Usage in Keras with TensorFlow Backend
keras 自适应分配显存 & 清理不用的变量释放 GPU 显存 Intro Are you running out of GPU memory when using keras or ten ...
- reentrantlock用于替代synchronized
1.①使用reentrantlock可以完成同样的功能 ②需要注意的是,必须要必须要必须要手动释放锁(重要的事情说三遍) ③使用syn锁定的话如果遇到异常,jvm会自动释放锁,但是lock必须 ...
- 神奇的负Margin
在做slide时候一般都是采用父元素超宽+overflow的做法,今天发现了用margin-right:-100%;可以让子元素全部重叠起来.效果也是不错的
- leetcode之二叉树的层序遍历
1.题目描述 2.题目分析 二叉树的层序遍历主要算法思想是使用 队列这一数据结构实现,这个数据结构多应用在和 图相关的算法.例如图的广度优先遍历就可以使用队列的方法实现.本题的关键在于如何识别出一层已 ...