摘要: 本文结合《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 的创建的更多相关文章

  1. spring基础:什么是框架,框架优势,spring优势,耦合内聚,什么是Ioc,IOC配置,set注入,第三方资源配置,综合案例spring整合mybatis实现

    知识点梳理 课堂讲义 1)Spring简介 1.1)什么是框架 源自于建筑学,隶属土木工程,后发展到软件工程领域 软件工程中框架的特点: 经过验证 具有一定功能 半成品 1.2)框架的优势 提高开发效 ...

  2. Java开发学习(十四)----Spring整合Mybatis及Junit

    一.Spring整合Mybatis思路分析 1.1 环境准备 步骤1:准备数据库表 Mybatis是来操作数据库表,所以先创建一个数据库及表 create database spring_db cha ...

  3. Spring整合MyBatis(三)sqlSessionFactory创建

    摘要: 本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 目录 一.SqlSessionFactoryBean的初始化 二.获取 ...

  4. Mybatis学习(六)————— Spring整合mybatis

    一.Spring整合mybatis思路 非常简单,这里先回顾一下mybatis最基础的根基, mybatis,有两个配置文件 全局配置文件SqlMapConfig.xml(配置数据源,全局变量,加载映 ...

  5. Mybatis(六) Spring整合mybatis

    心莫浮躁~踏踏实实走,一步一个脚印,就算不学习,玩,能干嘛呢?人生就是那样,要找点有意思,打发时间的事情来做,而钻研技术,动脑动手的过程,还是比其他工作更有意思些~ so,努力啥的都是强迫自己做自以为 ...

  6. Spring学习总结(六)——Spring整合MyBatis完整示例

    为了梳理前面学习的内容<Spring整合MyBatis(Maven+MySQL)一>与<Spring整合MyBatis(Maven+MySQL)二>,做一个完整的示例完成一个简 ...

  7. Spring学习总结(五)——Spring整合MyBatis(Maven+MySQL)二

    接着上一篇博客<Spring整合MyBatis(Maven+MySQL)一>继续. Spring的开放性和扩张性在J2EE应用领域得到了充分的证明,与其他优秀框架无缝的集成是Spring最 ...

  8. 深入源码理解Spring整合MyBatis原理

    写在前面 聊一聊MyBatis的核心概念.Spring相关的核心内容,主要结合源码理解Spring是如何整合MyBatis的.(结合右侧目录了解吧) MyBatis相关核心概念粗略回顾 SqlSess ...

  9. 分析下为什么spring 整合mybatis后为啥用不上session缓存

    因为一直用spring整合了mybatis,所以很少用到mybatis的session缓存. 习惯是本地缓存自己用map写或者引入第三方的本地缓存框架ehcache,Guava 所以提出来纠结下 实验 ...

  10. 2017年2月16日 分析下为什么spring 整合mybatis后为啥用不上session缓存

    因为一直用spring整合了mybatis,所以很少用到mybatis的session缓存. 习惯是本地缓存自己用map写或者引入第三方的本地缓存框架ehcache,Guava 所以提出来纠结下 实验 ...

随机推荐

  1. Git 学习之git 起步(一)

    起步 本章介绍开始使用 Git 前的相关知识.我们会先了解一些版本控制工具的历史背景,然后试着让 Git 在你的系统上跑起来,直到最后配置好,可以正常开始开发工作.读完本章,你就会明白为什么 Git ...

  2. 线上Bug修复流程

  3. 切换Fragment时实现数据保持

    摘要 Fragment设计初衷是为了简化不同屏幕分辨率的开发难度,他将代表一个功能的UI及其相关数据看做一个模块,以便达到复用.可以将Fragment看作是一个可以嵌入布局中的activity,有自己 ...

  4. web 应用请求乱码问题

    背景 作为非西欧语系的国家,总是要处理编码问题 使用java编码解码 @Test public void coderTest() throws UnsupportedEncodingException ...

  5. SpringBoot 之HelloController

    1.搭建环境 1.1 新建一个maven项目,一路下一步 1.2 打开pom 文件,首先增加<parent></parent>标签: <parent> <gr ...

  6. 【java8】慎用java8的foreach循环(作废)

    +警告 这篇文章作废掉,是由一个错误的测试方法得到的一个错误结论,后续修正结果正在测试,将贴上. 准确测试已完成:http://www.cnblogs.com/yiwangzhibujian/p/69 ...

  7. Pig order by用法举例

    sorted = order data by $0;   数值类型按照数值大小比较 chararray类型按照字符的字典顺序比较 bytearray按照字节的字典顺序比较 复杂类型(map.tuple ...

  8. <![CDATA[文本内容]]>

    DTD中的属性类型 全名:character data 在标记CDATA下,所有的标记.实体引用都被忽略,而被XML处理程序一视同仁地当做字符数据看待, CDATA的形式如下: <[CDATA[ ...

  9. Shell: extract more from listener.log (分析oracle监听日志)

    最近遇到了两起数据库连接数不足的问题, 通常都会预留一些会话增加的情况, 但在一些特殊情况下如连接风暴(logon storm), 如果在监听中没有做rate限流,对数据库来说巨大的冲击可能会导致数据 ...

  10. Fuckey V1.0 Beta版发布!!!

    Fuckey,以前叫FullNexus4,只因为当时想做一个软件给自己的Nexus 4,方便方便一下,不过这名字感觉太局限了,毕竟很多朋友不是使用的Nexus 4的手机,但却还是使用了FullNexu ...