前言:入职新公司,SpringBoot和Mybatis都被封装了一次,光用而不知道原理实在受不了,于是开始恶补源码,由于刚开始比较浅,存属娱乐,大神勿喷。

就如网上的流传的SpringBoot与Mybatis整合两种方式

一.使用 pom文件使用:org.mybatis.spring.boot 依赖

坐标:

<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>xxxxx</version> 通过pom.xml能够看到该依赖的其他依赖文件

注意这个org.mybatis.spring....autoconfigure包,找到这个包,点开META-INF目录下,找到spring.factories文件   这是自动配置mybatis注解,mapper存放位置等的地方。

这里如果EnableAutoConfigurationImportSelector不懂的可以看 https://www.jianshu.com/p/464d04c36fb1

,这里不在详细解释,只要知道是Spring的一个自动配置的注解,通过它会自动加载类。

进入 MybatisAutoConfiguration


@Configuration
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
@ConditionalOnBean({DataSource.class})
@EnableConfigurationProperties({MybatisProperties.class})
@AutoConfigureAfter({DataSourceAutoConfiguration.class})
public class MybatisAutoConfiguration {
private static final Logger logger = LoggerFactory.getLogger(MybatisAutoConfiguration.class);
private final MybatisProperties properties;
private final Interceptor[] interceptors;
private final ResourceLoader resourceLoader;
private final DatabaseIdProvider databaseIdProvider;
private final List<ConfigurationCustomizer>configurationCustomizers;
MybatisProperties 类是接受Mybatis配置文件的类
@ConfigurationProperties(
prefix = "mybatis"
)
public class MybatisProperties {
public static final String MYBATIS_PREFIX = "mybatis";
private String configLocation;
private String[] mapperLocations;
private String typeAliasesPackage;
private String typeHandlersPackage;
private boolean checkConfigLocation = false;
private ExecutorType executorType;
private Properties configurationProperties;
@NestedConfigurationProperty
private Configuration configuration;
config-location    Location of MyBatis xml config file.
check-config-location Indicates whether perform presence check of the MyBatis xml config file.
mapper-locations Locations of Mapper xml config file.
type-aliases-package Packages to search for type aliases. (Package delimiters are ",; \t\n")
type-handlers-package Packages to search for type handlers. (Package delimiters are ",; \t\n")
executor-type Executor type: SIMPLE, REUSE, BATCH.
configuration-properties Externalized properties for MyBatis configuration. Specified properties can be used as placeholder on MyBatis config file and Mapper file. For detail see the MyBatis reference page
configuration A MyBatis Configuration bean. About available properties see the MyBatis reference page. NOTE This property cannot be used at the same time with the config-location.
@PostConstruct 在初始化的时候执行:加载配置文件
    @PostConstruct
public void checkConfigFileExists() {
if (this.properties.isCheckConfigLocation() && StringUtils.hasText(this.properties.getConfigLocation())) {
Resource resource = this.resourceLoader.getResource(this.properties.getConfigLocation());
Assert.state(resource.exists(), "Cannot find config location: " + resource + " (please add config file or check your Mybatis configuration)");
} @Bea@ConditionalOnMissingBean 自动创建 sqlSessionFactorySqlSessionTemplate


下面的静态内部类 AutoConfiguredMapperScannerRegistrar 会在运行期间@Mapper注解,使用过@Mapper的Mapper接口
自动的生成动态代理mapper接口
public static class AutoConfiguredMapperScannerRegistrar implements BeanFactoryAware, ImportBeanDefinitionRegistrar, ResourceLoaderAware {
private BeanFactory beanFactory;
private ResourceLoader resourceLoader; public AutoConfiguredMapperScannerRegistrar() {
} public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
MybatisAutoConfiguration.logger.debug("Searching for mappers annotated with @Mapper");
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry); try {
if (this.resourceLoader != null) {
scanner.setResourceLoader(this.resourceLoader);
} List<String> packages = AutoConfigurationPackages.get(this.beanFactory);
if (MybatisAutoConfiguration.logger.isDebugEnabled()) {
Iterator var5 = packages.iterator(); while(var5.hasNext()) {
String pkg = (String)var5.next();
MybatisAutoConfiguration.logger.debug("Using auto-configuration base package '{}'", pkg);
}
}
          //注册注解
scanner.setAnnotationClass(Mapper.class);
scanner.registerFilters();
scanner.doScan(StringUtils.toStringArray(packages));
} catch (IllegalStateException var7) {
MybatisAutoConfiguration.logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.", var7);
} } public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
} public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
}

注意:要是此时在SpringBoot启动类上使用了@MapperScan()注解,那么此时将进入@Import 导入的类,进行注册
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({MapperScannerRegistrar.class})
public @interface MapperScan {
String[] value() default {}; String[] basePackages() default {}; Class<?>[] basePackageClasses() default {}; Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class; Class<? extends Annotation> annotationClass() default Annotation.class; Class<?> markerInterface() default Class.class; String sqlSessionTemplateRef() default ""; String sqlSessionFactoryRef() default ""; Class<? extends MapperFactoryBean> factoryBean() default MapperFactoryBean.class;
}

在 MapperScannerRegistrar的 registerBeanDefinitions 方法用ClassPathMapperScanner进行注册,使用doScan扫描包

此时注册的注解需要annotationClass的值,

    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
if (this.resourceLoader != null) {
scanner.setResourceLoader(this.resourceLoader);
} Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
if (!Annotation.class.equals(annotationClass)) {
scanner.setAnnotationClass(annotationClass);
} Class<?> markerInterface = annoAttrs.getClass("markerInterface");
if (!Class.class.equals(markerInterface)) {
scanner.setMarkerInterface(markerInterface);
} Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
if (!BeanNameGenerator.class.equals(generatorClass)) {
scanner.setBeanNameGenerator((BeanNameGenerator)BeanUtils.instantiateClass(generatorClass));
} Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
scanner.setMapperFactoryBean((MapperFactoryBean)BeanUtils.instantiateClass(mapperFactoryBeanClass));
} scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef"));
scanner.setSqlSessionFactoryBeanName(annoAttrs.getString("sqlSessionFactoryRef"));
List<String> basePackages = new ArrayList();
String[] var10 = annoAttrs.getStringArray("value");
int var11 = var10.length; int var12;
String pkg;
for(var12 = 0; var12 < var11; ++var12) {
pkg = var10[var12];
if (StringUtils.hasText(pkg)) {
basePackages.add(pkg);
}
} var10 = annoAttrs.getStringArray("basePackages");
var11 = var10.length; for(var12 = 0; var12 < var11; ++var12) {
pkg = var10[var12];
if (StringUtils.hasText(pkg)) {
basePackages.add(pkg);
}
} Class[] var14 = annoAttrs.getClassArray("basePackageClasses");
var11 = var14.length; for(var12 = 0; var12 < var11; ++var12) {
Class<?> clazz = var14[var12];
basePackages.add(ClassUtils.getPackageName(clazz));
} scanner.registerFilters();
scanner.doScan(StringUtils.toStringArray(basePackages));
}
若既不使用@MapperScan 注解 也不使用@Mapper注解,则Mapper类不能生成代理对象,则在@Autowire注入时,会报错
 nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException

二 使用Mybatis-Spring整合

该整合jar包含的类

 

spring.handlers中内容找到处理器org.mybatis.spring.config.NamespaceHandler

http\://mybatis.org/schema/mybatis-spring=org.mybatis.spring.config.NamespaceHandler

处理器中会有解析器MapperScannerBeanDefinitionParser来解析这个xml

    public void init() {
this.registerBeanDefinitionParser("scan", new MapperScannerBeanDefinitionParser());
}

在  MapperScannerBeanDefinitionParser进行注册

public synchronized BeanDefinition parse(Element element, ParserContext parserContext) {
ClassPathMapperScanner scanner = new ClassPathMapperScanner(parserContext.getRegistry());
ClassLoader classLoader = scanner.getResourceLoader().getClassLoader();
XmlReaderContext readerContext = parserContext.getReaderContext();
scanner.setResourceLoader(readerContext.getResourceLoader()); String annotationClassName;
String markerInterfaceClassName;
String nameGeneratorClassName;
try {
annotationClassName = element.getAttribute("annotation");
if (StringUtils.hasText(annotationClassName)) {
Class<? extends Annotation> markerInterface = classLoader.loadClass(annotationClassName);
scanner.setAnnotationClass(markerInterface);
} markerInterfaceClassName = element.getAttribute("marker-interface");
if (StringUtils.hasText(markerInterfaceClassName)) {
Class<?> markerInterface = classLoader.loadClass(markerInterfaceClassName);
scanner.setMarkerInterface(markerInterface);
} nameGeneratorClassName = element.getAttribute("name-generator");
if (StringUtils.hasText(nameGeneratorClassName)) {
Class<?> nameGeneratorClass = classLoader.loadClass(nameGeneratorClassName);
BeanNameGenerator nameGenerator = (BeanNameGenerator)BeanUtils.instantiateClass(nameGeneratorClass, BeanNameGenerator.class);
scanner.setBeanNameGenerator(nameGenerator);
}
} catch (Exception var11) {
readerContext.error(var11.getMessage(), readerContext.extractSource(element), var11.getCause());
} annotationClassName = element.getAttribute("template-ref");
scanner.setSqlSessionTemplateBeanName(annotationClassName);
markerInterfaceClassName = element.getAttribute("factory-ref");
scanner.setSqlSessionFactoryBeanName(markerInterfaceClassName);
scanner.registerFilters();
nameGeneratorClassName = element.getAttribute("base-package");
scanner.scan(StringUtils.tokenizeToStringArray(nameGeneratorClassName, ",; \t\n"));
return null;
}

也可以使用@MapperScanner注解 在 MapperScannerConfigurer进行注册

 public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
if (this.processPropertyPlaceHolders) {
this.processPropertyPlaceHolders();
} ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
scanner.setAddToConfig(this.addToConfig);
scanner.setAnnotationClass(this.annotationClass);
scanner.setMarkerInterface(this.markerInterface);
scanner.setSqlSessionFactory(this.sqlSessionFactory);
scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
scanner.setResourceLoader(this.applicationContext);
scanner.setBeanNameGenerator(this.nameGenerator);
scanner.registerFilters();
scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ",; \t\n"));
}

还可以在 xml文档里注册 MapperScannerConfigurer自动管理(同上,一个xml一个注解)

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="org.mybatis.spring.sample.mapper" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>

注意: org-mybatis-spring.boot为: 1.3.0  mybatis-spring:1.3.1 ,mybatis:3.4.4

SpringBoot与Mybatis整合方式01(源码分析)的更多相关文章

  1. 线程系列1--Java创建线程的几种方式及源码分析

    线程--创建线程的几种方式及源码分析 开始整理下线程的知识,感觉这块一直是盲区,工作中这些东西一直没有实际使用过,感觉也只是停留在初步的认识.前段时间一个内推的面试被问到,感觉一脸懵逼.面试官说,我的 ...

  2. springboot bean的循环依赖实现 源码分析

    springboot bean的循环依赖实现 源码分析 本文基于springboot版本2.5.1 <parent> <groupId>org.springframework. ...

  3. FatFsVersion0.01源码分析

    目录 一.API的函数功能简述 二.FATFS主要数据结构 1.FAT32文件系统的结构 2.FATFS主要数据结构 ①   FATFS ②   DIR ③  FIL ④  FILINFO ⑤  wi ...

  4. Mybatis 插件使用及源码分析

    Mybatis 插件 Mybatis插件主要是通过JDK动态代理实现的,插件可以针对接口中的方法进行代理增强,在Mybatis中比较重要的接口如下: Executor :sql执行器,包含多个实现类, ...

  5. SpringBoot启动代码和自动装配源码分析

    ​ 随着互联网的快速发展,各种组件层出不穷,需要框架集成的组件越来越多.每一种组件与Spring容器整合需要实现相关代码.SpringMVC框架配置由于太过于繁琐和依赖XML文件:为了方便快速集成第三 ...

  6. Mybatis【2.2】-- Mybatis关于创建SqlSession源码分析的几点疑问?

    代码直接放在Github仓库[https://github.com/Damaer/Mybatis-Learning ],可直接运行,就不占篇幅了. 目录 1.为什么我们使用SQLSessionFact ...

  7. Android源码分析-消息队列和Looper

    转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/17361775 前言 上周对Android中的事件派发机制进行了分析,这次博主 ...

  8. 安卓MonkeyRunner源码分析之工作原理架构图及系列集合

    花了点时间整理了下MonkeyRunner的工作原理图,请配合本人博客里面MonkeyRunner其他源码分析文章进行阅读.下面整理成相应系列列表方便大家阅读: MonkeyRunner源码分析之-谁 ...

  9. Ribbon源码分析(一)-- RestTemplate 以及自定义负载均衡算法

    如果只是想看ribbon的自定义负载均衡配置,请查看: https://www.cnblogs.com/yangxiaohui227/p/13186004.html 注意: 1.RestTemplat ...

随机推荐

  1. struts2(三)之表单参数自动封装与参数类型自动转换

    前言 对struts2的使用不外乎这几点,参数自动封装,拦截器的使用,数据校验,ognl表达(值栈和actionContext的讲解),struts2的标签,struts2的国际化, struts2的 ...

  2. BZOJ 3098: Hash Killer II(新生必做的水题)

    3098: Hash Killer II Time Limit: 5 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 1555  Solved: ...

  3. oracle ebs form开发总结

    item的布局千万不要去乱动,只要调好长宽和y轴的坐标就好了.form内部集成了很多代码对布局进行动态的调整,而且有一些代码的长宽什么的还是写死了的,我们一动,form可能就识别不了了,然后就显示出来 ...

  4. 微信小程序 登录流程规范解读

    一. 官方登录时序图 二. 简单理解 这里仅按照官方推荐的规范来 0. 前置条件 一共有三端: - 微信小程序客户端 - 第三方服务器端(自己搭建) - 微信服务器端 1. 客户端获得code,并将c ...

  5. 使用nginx处理静态资源请求,其余交给node

    由于项目后台使用的是node,然而node不适合对静态资源的处理,因为他的异步处理(事件轮询)机制,所以更擅长的是密集I/O型的应用,所以我就有了一个想法,使用nginx来做反向代理,当请求的是静态资 ...

  6. 复选框之checked属性

    今天无意中看到同事在学习复选框里面的checked属性的应用,当时看了一下,感觉熟悉而又陌生,发现checked属性其实还是挺奇怪的,感觉这里很有必要做一下笔记: 1.html中的checked属性. ...

  7. [UWP]使用Acrylic

    1. 前言 在 如何使用Fluent Design System 这篇文章里已经简单介绍过Reveal的用法,这篇再详细介绍其它内容. 自Windows 8 放弃Aero后,群众对毛玻璃回归的呼声一致 ...

  8. Thinkphp+Nginx(PHPstudy)下报的404错误,403错误解决

    最近一个TP5的项目说放到Nginx下测试看看,下载个 PHPstudy,放到WWW下,配置好域名,直接给个报个404: 解决方法: 1.先在phpstudy下配置好域名目录指向项目下的public下 ...

  9. thinkphp3.2后台模块怎么添加(admin),直接复制Home?还是在入口文件生成?

    1.都可以,复制home改下命名空间也行,在入口添加下参数自动生成也行 2ThinkPHP3.2后支持模块化开发,在Home目录的同级目录下创建一个新的文件夹,命名为Admin,或者就如你自己所说,直 ...

  10. forward和redirect

    Forward和Redirect代表了两种请求转发方式:直接转发和间接转发. 直接转发方式(Forward),客户端和浏览器只发出一次请求,Servlet.HTML.JSP或其它信息资源,由第二个信息 ...