Spring源码深度解析 整合MyBatis总结

MyBatis 独立使用

建立 PO
在这里插入图片描述
在这里插入图片描述
建立 Mapper
在这里插入图片描述
建立配置文件
配置文件的基本结构
在这里插入图片描述
configuration :根元素
properties 定义配置外在化
settings 一些全局性的配置
typeAliases :为一些类定义别名
typeHandlers :定义类型处理,也就是定义 Java 类型与数据库中的数据类型之间的转
换关系
objectFactory :用于指定结果集对象的实例是如何创建的
plugins: MyBatis 的插件,插件可以修改 MyBatis 内部的运行规则
environments 环境
environment 配置 MyBatis 的环境
transactionManager :事务管理器
dataSource 数据源
mappers 指定映射文件或映射类
在这里插入图片描述
建立映射文件
在这里插入图片描述
在这里插入图片描述
建立测试类
在这里插入图片描述
在这里插入图片描述

Spring 整合 MyBatis
Spring 配置文件
在这里插入图片描述
MyBatis 配置文件
在这里插入图片描述
映射文件(保持不变)
在这里插入图片描述
测试
在这里插入图片描述

源码分析
sqlSessionFactory创建
对于配置文件的读取解析, Spring 应该通过 org.mybatis.Spring.
SqISessionFactoryBean 封装了 MyBatis 中的实现 这个类的层次结构
在这里插入图片描述
InitializingBean 实现此接口的 bean 会在初始化时调用其 afterPropertiesSet 方法来进
行 bean 的逻辑初始化
FactoryBean :一旦某个 bean 实现次接 口,那么通过 getBean 方法获取 bean 时其 实是
获取此类的 getObject()返回的 实例

SqlSessionFactoryBean 的初始化
在这里插入图片描述
此函数主要目的就是对于 sqlSessionFactory 的初始化,SqlSessionFactory 是所有 MyBatis 功能的基础
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
从函数中可以看到 ,尽管我们还是习惯于将 MyBatis 的配置与 Spring 的配置独立出来
但是,这并不代表 Spring 中的配置不支持直接配置。 也就是说,在上面提供的示例中,完全
可以取消配置中的 configLocation 属性 ,而把其中的属性直接写在 SqlSessionFactoryBean 中
在这里插入图片描述
在这里插入图片描述
如果只按照常用的配置,那么我们只需要在函数最开始按照如下方式处理
configuration:
在这里插入图片描述
获取 SqlSessionFactoryBean 实例
在这里插入图片描述
MapperFactoryBean 的创建
对于单独使用 MyBatis 的时候调用数据库接口的方式是:
在这里插入图片描述
而对于 Spring 的创建方式
在这里插入图片描述
Spring 中获取的名为 userMapper 的 bean 其实是与单独使用 MyBatis 完成了一样的功
能,那么可以推断,在 bean 的创建过程中一定是使用了 MyBatis 中的原生方法
sq!Sessi on. getMapper(U serMapper.class)进行了再一次封装 结合配置文件,我们把分析目标转向
org.mybatis.Spring.mapper. MapperFactoryBean ,初步推测其中的逻辑应该在此类中实现 查看类的层次结构图 MapperFactoryBean
在这里插入图片描述

MapperFactoryBean 的初始化
在这里插入图片描述
MapperFactoryBean 的初始化包括对 DAO 配置的验证以
及对 DAO 的初始工作,其中 initDao ()方法是模板方法 ,设计为留给子类做进一步逻辑处理
而 checkDaoConfig()才是重点
在这里插入图片描述
在这里插入图片描述
super.check.DaoConfig()在 SqlSessionDaoSupport 类中实现,代码如下:
在这里插入图片描述
Spring 做了以下几个方面的工作
父类中对于 sqlSession 不为空的验证
sqlSession 作为根据接口创建映射器代理的接触类一定不可以为空 ,而 sqISession 的初始化
工作是在设定其 sqlSessionFactory 属性时完成的
在这里插入图片描述
也就是说,对于下面的配置如果忽略了对于 sqlSessionFactory 属性的设置,那么在此时就
会被检测出来
在这里插入图片描述
映射接口的验证
接口是映射器的基础, sqISession 会根据接口动态创建相应的代理类,所以接口必不可少

映射文件存在性验证

获取 MapperFactoryBean 的实例
由于 MapperFactoryBean 实现了 FactoryBean 接口, 所以当通过 getBean 方法获取对应实例
的时候其实是获取该类的 getObject()函数返回的实例
在这里插入图片描述

MapperScannerConfigurer
在 applicationContext.xml 中配置了 userMapper 供需要时使用 但如果需要用到的映射器
较多的话,采用这种配置方式就显得很低效 为了解决这个问题,我们可以使用 MapperScanner
Configurer ,让它扫描特定的包,自动帮我们成批地创建映射器 这样一来 ,就能大大减少配
置的工作量
在这里插入图片描述
在这里插入图片描述

通过上面的配置, Spring 就会帮助我们对 test.mybatis.dao 下面的所有接口进行自动的注入,
而不需要为每个接口重复在 Spring 配置文件中进行声明了 那么,这个功能又是如何做到的呢
MapperScannerConfigurer 中又有哪些核心操作呢 首先查看类的层次结构图
在这里插入图片描述
查找类的 afterPropettiesSet 方法来看看类的初始化逻辑
在这里插入图片描述
afterPropertiesSet()方法除了一句对 basePackage属性的验证代码外并没有太多的逻辑实现
再次查看 MapperScannerConfigurer 类层次结构图中感兴趣的接口 ,发现了 BeanDefinitionRegistryPostProcessor
与 BeanFactoryPostProcessor, Spring 在初始化的过程中同样会保证这两个接口的调用
首先查看 MapperScannerConfigurer 类中对于 BeanFactoryPostProcessor 接口的实现:
在这里插入图片描述
没有任何逻辑实现
查看MapperScannerConfigurer类中对于 BeanDefinitionRegistryPostProcessor 接口的实现
在这里插入图片描述

processPropertyPlaceHolders 属性的处理
在这里插入图片描述
在这里插入图片描述
BeanDefinitionRegistries 会在应用启动的时候调用,并且会早于 BeanFactory PostProcessors 的调
用,这就意味着 PropertyResourceConfigurers 还没有被加载所有对于属性文件的引用将会失效
为避免此种情况发生,此方法手动地找出定义的 PropertyResourceConfigurers 并进行提前调用
以保证对于属性的引用可以正常工作

如要创建配置文件如 test.properties 并添加属性对
在这里插入图片描述
然后在 Spring 配置文件中加入属性文件解析器:
在这里插入图片描述
修改 MapperScannerConfigurer 类型的 bean 的定义
在这里插入图片描述
这个配置并没有达到预期的效果,因为在解析${basePackage }的时候
PropertyPlaceholderConfigurer 还没有被调用,也就是属性文件中的属性还没有加载至内存中,
Spring 还不能直接使用它 为了解决这个问题, Spring 提供了 processPropertyPlaceHolders 属性,
需要这样配置 MapperScannerConfigurer 类型的 bean
在这里插入图片描述
通过 processPropertyPiaceHolders 属性的配置,将程序引人我们正在分析的 processProperty
PlaceHolders 函数中来完成属性文件的加载。这个函数所做的事情
找到所有已经注册的 PropertyResourceConfigurer 类型的 bean
模拟 Spring 中的环境来用处理器 这里通过使用 new DefaultListableBeanFactory ()来模
模 Spring 中的环境(完成处理器的调用后便失效),将映射的 bean ,也就是 MapperScanner
Configurer 类型 bean 注册到环境中来进行后理器的调用,处理器 PropertyPlaceholderConfigurer
调用完成的功能,即找出所有 bean 中应用属性文件的变量并替换。 也就是说,在处理器调用
后,模拟环境中模拟的 MapperScannerConfigurer 类型的 bean 如果有引人属性文件中的属性那
么已经被替换了,这时,再将模拟 bean 中相关的属性提取出来应用在真实的 bean 中

根据配置属性生成过滤器
属性设置后通过在 scanner.registerFilters()代码中生成对应的过滤器来控制扫描结果
在这里插入图片描述
在这里插入图片描述
根据之前属性的配置生成了对应的过滤器

annotationClass 属性处理

markerlnterface 属性处理

全局默认处理

package-info.java 处理
控制扫描文件 Spring 通过不同的过滤器完成,这些定义的过滤器
记录在了 includeFilters 和 excludeFilters 属性中
在这里插入图片描述

扫描 Java 文件
设置了相关属性以及生成了对应的过滤器后便可以进行文件的扫描了,扫描工作是由
ClassPath.MapperScanner 类型的实例 scanner 中的 scan 方法完成的
在这里插入图片描述
在这里插入图片描述
scan 是个全局方法,扫描工作通过 doScan(basePackages)委托给了 doScan 方法,同时,还包括
了 includeAnnotationConfig 属性的处理, AnnotationConfigUtils.registerAnnotation ConfigProcessors
(this.registry)代码主要是完成对于注解处理器的简单注册,比如 AutowiredAnnotationBeanPost
Processor RequiredAnnotationBeanPostProcessor 等,重点研究文件扫描功能的实现
在这里插入图片描述
在这里插入图片描述
Spring 中对于自动扫描的注册 声明 MapperScannerConfigurer 类型的 bean 目的是不需要我们对于每个接口都注
册一个 MapperFactoryBean 类型的对应的 bean ,但是,不在配置文件中注册并不代表这个 bean
不存在,而是在扫描的过程中通过编码的方式动态注册。实现过程在上面的函数中可以看得非常清楚
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
findCandidateComponents 方法根据传人的包路径信息并结合类文件路径拼接成文件的绝
对路径,同时完成了文件的扫描过程并且根据对应的文件生成了对应的 bean ,使用
ScannedGenericBeanDefinition 类型的 bean 承载信息, bean 中只记录了 resource 和 source 信息
这里,更感兴趣的是 isCandidateComponent(metadataReader),此句代码用于判断当前扫描
的文件是否符合要求,而之前注册的一些过滤器信息也正是在此时派上用场的
在这里插入图片描述
看到了之前加入过滤器的两个属性 excludeFilters 和 includeFilters ,井且知道对应的文
件是否符合要求是根据过滤器中的 match 方法所返回的信息来判断的,当然用户可以实现并注
册满足自己业务逻辑的过滤器来控制扫描的结果, metadataReader 中有你过滤所需要的全部文
件信息 至此,完成了文件的扫描过程的分析

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值