这篇笔记主要来就,mybatis是如何利用spring的扩展点来实现和spring的整合

1.mybatis和spring整合之后,我们就不需要使用sqlSession.selectOne()这种方式了,可以直接从spring容器中获取到接口的代理对象,然后调用对应的目标方法,那么,mybatis在将接口交给spring管理的时候,用到了三个扩展点:

1.1 factoryBean  mapperFactoryBean就是实现了factoryBean,然后,通过getObject方法来返回一个代理对象

1.2 mapperFactoryBean同时继承了SqlSessionDao,SqlSessionDao继承了DaoSupport,DaoSuppor有实现了InitializingBean,在初始化mybatis接口的时候,会调用DaoSupport的afterPropertiesSet()方法,也就是spring的初始化方法

1.3 mapperScannerRegistrar实现了ImportBeanDefinitionRegistrar接口,在registerBeanDefinitions方法中,会对mapperScan注解声明的包,进行扫描,class,扫描到beanDefinitionMap中,然后完成bean的初始化

2.mybatis在和spring整合的时候,需要用到一个注解 @MapperScan,这个注解使用了@Import,引入了mapperScannerRegistrar,关于import注解的作用,在spring源码解析(一)中有介绍,不详细说了,在将类put到beanDefinitionMap中的时候,会执行mapperScannerRegistrar的registryBeanDefintions方法,这时候,会调用doScan方法,将mapperScan对应包下的class扫描出来,放到beanDefinitionMap中,这里要提的一个点是:

@ComponentScan和@MapperScan,两个注解的包可能会一样,扫描出来的所有.class文件都是一样的,但是注入到beanDefinitionMap中的时候,ComponentScan注解注入的是@Component、@Controller、@Repository、@Service注解对应的class,mapperScan注入的是接口对应的类,关于这个点,我debug看过源码,在后面会把代码贴出来

 public Set<BeanDefinitionHolder> doScan(String... basePackages) {
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
if (beanDefinitions.isEmpty()) {
this.logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.");
} else {
this.processBeanDefinitions(beanDefinitions);
} return beanDefinitions;
}

这个方法就是mapperScannerRegistrar中要调用的扫描方法,supper.doScan()会把包下所有的接口注入到beanDefinitionMap中,在注入完之后,会对mybatis的beanDefinition进行一些处理,在第六行的这个方法中,

1.把当前beanDefinition的beanClass设置为mapperFactoryBean.calss,这样设置,是为了spring在对bean进行初始化的时候,会执行bean的初始化方法(就是上面说到的afterPropertiesSet())方法,在执行mybatis接口的初始化方法的时候,会根据beanClass,来调用mapperFactoryBean的getObject()方法来返回一个代理对象;

2.把beanDefinition的注入模型(autowiredMode)设置为2(byType);这里会设计到spring的注入模型,简单而言,如果是byType,那么,就不需要在bean中添加@Autowired和@Resource,只需要提供set方法即可(注意:这里的byType和@Resource不一样)


由于mapperFatoryBean继承了daoSupport,daoSupport又实现了InitializingBean,所以,spring容器在对mybatis的接口进行初始化之后,进行属性注入,然后会进行初始化,调用DaoSuppro的afterPropertySet方法,其中,会调用子类的checkDaoConfig()方法,在checkDaoConfig中,调用了configuration.addMapper(this.mapperInterface);这个方法就是mybatis中,将class放到knownMappers这个map的操作

 protected void checkDaoConfig() {
super.checkDaoConfig();
Assert.notNull(this.mapperInterface, "Property 'mapperInterface' is required");
Configuration configuration = this.getSqlSession().getConfiguration();
if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
try {
configuration.addMapper(this.mapperInterface);
} catch (Exception var6) {
this.logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", var6);
throw new IllegalArgumentException(var6);
} finally {
ErrorContext.instance().reset();
}
} }

那mapperFactoryBean的getObject()方法是在什么时候执行呢?假如说我们在service中注入了mybatis的dao接口,在实例化service的时候,会进行属性注入,属性注入的时候,会发现,service中需要注入dao,这时候,会调用getBean()从spring容器中获取,如果dao,没有实例化,就会去实例化,在实例化完成之后,放到单实例池中,然后,会调用getObject()

在调用getObject的时候,会通过jdk动态代理来生成一个代理对象

 public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
} else {
try {
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception var5) {
throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
}
}
}

这里生成代理对象和原生mybatis生成代理对象有一个区别,就是这里的sqlSession,原生的,用的是DefaultSqlSession,mybatis和spring整合之后,这里用的是sqlSessionTemplate,那为什么会是sqlSessionTemplate呢?

在mapperFactoryBean的父类,SqlSessionDaoSupport中,会对sqlSession赋值,这时候,是直接new SqlSessionTemplate(SqlSessionFactory),所以,在和spring整合之后,mybatis用的sqlSession是sqlSessionTemplate

在实际调用目标方法的时候,会被mapperProxy的invoke方法拦截,和原生mybatis不同的时候,在判断是select还是update,之后,原生的mybatis会调用sqlSession.selectOne();和spring整合之后,会调用SqlSessionTemplate.selectOne(),然后再调用sqlSessionInterceptor.invoke()方法

mybatis源码学习(二)--mybatis+spring源码学习的更多相关文章

  1. Sping学习笔记(一)----Spring源码阅读环境的搭建

    idea搭建spring源码阅读环境 安装gradle Github下载Spring源码 新建学习spring源码的项目 idea搭建spring源码阅读环境 安装gradle 在官网中下载gradl ...

  2. (转)MyBatis框架的学习(二)——MyBatis架构与入门

    http://blog.csdn.net/yerenyuan_pku/article/details/71699515 MyBatis框架的架构 MyBatis框架的架构如下图: 下面作简要概述: S ...

  3. Quartz学习--二 Hello Quartz! 和源码分析

    Quartz学习--二  Hello Quartz! 和源码分析 三.  Hello Quartz! 我会跟着 第一章 6.2 的图来 进行同步代码编写 简单入门示例: 创建一个新的java普通工程 ...

  4. [spring源码学习]二、IOC源码——配置文件读取

    一.环境准备 对于学习源码来讲,拿到一大堆的代码,脑袋里肯定是嗡嗡的,所以从代码实例进行跟踪调试未尝不是一种好的办法,此处,我们准备了一个小例子: package com.zjl; public cl ...

  5. 框架源码系列六:Spring源码学习之Spring IOC源码学习

    Spring 源码学习过程: 一.搞明白IOC能做什么,是怎么做的  1. 搞明白IOC能做什么? IOC是用为用户创建.管理实例对象的.用户需要实例对象时只需要向IOC容器获取就行了,不用自己去创建 ...

  6. Java开发学习(二十一)----Spring事务简介与事务角色解析

    一.Spring事务简介 1.1 相关概念介绍 事务作用:在数据层保障一系列的数据库操作同成功同失败 Spring事务作用:在数据层或业务层保障一系列的数据库操作同成功同失败 数据层有事务我们可以理解 ...

  7. (原创)mybatis学习二,spring和mybatis的融合

    mybatis学习一夯实基础 上文介绍了mybatis的相关知识,这一节主要来介绍mybaits和spring的融合 一,环境搭建 1,jar包下载,下载路径为jar包 2,将包导入到java工程中 ...

  8. 框架源码系列七:Spring源码学习之BeanDefinition源码学习(BeanDefinition、Annotation 方式配置的BeanDefinition的解析)

    一.BeanDefinition 1. bean定义都定义了什么? 2.BeanDefinition的继承体系  父类: AttributeAccessor: 可以在xml的bean定义里面加上DTD ...

  9. springMvc源码学习之:spring源码总结

    转载自:http://www.cnblogs.com/davidwang456/p/4213652.html spring beans下面有如下源文件包: org.springframework.be ...

随机推荐

  1. Swift - 给UICollectionview设置组背景和圆角

    钟情圆角怎么办 最近由于我们的UI钟情于圆角搞得我很方,各种圆角渐变,于是就有了下面这篇给UICollection组设置圆角和背景色的诞生,不知道在我们平时有没有遇到这样子的一些需求,就是按照每一组给 ...

  2. 腾讯视频缓存 tdl 转 mp4

    找到腾讯视频->设置,看下缓存文件的目录地址,然后cmd,通过命令进行转化.  copy/b *.tdl 1.mp4

  3. ThinkPHP3.2.2实现持久登录(记住我)功能的方法

    实现持久登录,即用户在登录时,勾选了"记住我"之后,无论是否关闭浏览器,只要不退出登录,在指定的时间内始终保持登录状态(缺点是在另一台电脑上登录过后,之前那台电脑就不能继续保持登录 ...

  4. mysql那些事(4)建库建表编码的选择

    mysql建数据库或者建表的时候会遇到选择编码的问题,以前我们都是习惯性的选择utf8,但是在mysql在5.5.3版本后加了utf8mb4的编码,utf8mb4可以存4个字节Unicode,mb4就 ...

  5. 《Windows内核安全与驱动开发》 5.1&5.2 内核与应用方面的编程

    <Windows内核安全与驱动开发>阅读笔记 -- 索引目录 <Windows内核安全与驱动开发>  5.1&5.2 内核与应用方面的编程 一.生成控制设备 如果一个驱 ...

  6. pringBoot-MongoDB 索引冲突分析及解决【华为云技术分享】

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/devcloud/article/detai ...

  7. 基于webpack实现多html页面开发框架四 自动写入多入口,自动插入多个htmlWebpackPlugin插件

    一.解决什么问题      1.手写页面多入口,一个一个输入太麻烦,通过代码实现      2.手写多个htmlWebpackPlugin插件太麻烦,通过代码实现 二.多入口代码实现 //读取所有.j ...

  8. 侠梦说pinpoint--界面上的图标之AgetnInfo数据研究

    前言 在启动一个挂载pinpoint的springboot项目的时候,界面上显示成了jboss的图标,所以今天研究了一下这个数据是怎么来的. 我们知道不同图标和服务类型有关,服务不同,图标就不同,这在 ...

  9. 【广州.NET社区推荐】【译】Visual Studio 2019 中 WPF & UWP 的 XAML 开发工具新特性

    原文 | Dmitry 翻译 | 郑子铭 自Visual Studio 2019推出以来,我们为使用WPF或UWP桌面应用程序的XAML开发人员发布了许多新功能.在本周的 Visual Studio ...

  10. spring security 权限安全认证框架-入门(一)

    spring security 概述: Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架.它是保护基于spring的应用程序的实际标准. Spring Security ...