Springboot整合Mybatis,MybatisPlus源码分析,自动装配实现包扫描源码

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
简介: 该文档详细介绍了如何在Springboot Web项目中整合Mybatis,包括添加依赖、使用`@MapperScan`注解配置包扫描路径等步骤。若未使用`@MapperScan`,系统会自动扫描加了`@Mapper`注解的接口;若使用了`@MapperScan`,则按指定路径扫描。文档还深入分析了相关源码,解释了不同情况下的扫描逻辑与优先级,帮助理解Mybatis在Springboot项目中的自动配置机制。

1.简单项目:

我这里有一个简单的Springboot的Web项目,需要添加Springboot整合mybatis或者是mybatisPlus的依赖,这里我就以mybatis为例了,mybatisPlus跟mybatis是差不多的,首先添加依赖:

xml

代码解读

复制代码

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.2</version>
        </dependency>

Springboot的主启动类:使用MapperScan注解配置了一个包扫描的路径。

less

代码解读

复制代码

@SpringBootApplication
@MapperScan("com.atlx")
public class Springboot2DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(Springboot2DemoApplication.class, args);
    }
}

如果我们不使用@MapperScan注解配置包扫描的路径的话,Springboot在启动的时候也会去扫描Mapper接口,但是扫描的路径跟Springboot启动扫描类生成BeanDefinition的路径是一样的,并且还只会去扫描加了@Mapper注解的类。但是如果我们使用了@MapperScan注解并且配置了扫描的路径的话那么Springboot就会根据我们配置的路径去扫描Mapper接口。

所以下面我们的分析就是根据有没有加@MapperScan注解来分析。

2.没有加@MapperScan注解:

如果一个Springboot项目中没有加@MapperScan注解的话,那么在扫描Mapper接口的时候Springboot回去扫描加了@Mapper注解的接口,下面我们通过源码进行分析:

首先在idea中找到Springboot整合mybatis的依赖包:

编辑

找到里面对应的spring.factories文件:

ini

代码解读

复制代码

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration,\
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

它里面有对应的springboot整合mybatis的自动配置文件:MybatisAutoConfiguration,进入自动配置文件:里面有一个非常核心的内部类: MapperScannerRegistrarNotFoundConfiguration

less

代码解读

复制代码

    @Configuration
    @Import({AutoConfiguredMapperScannerRegistrar.class})
    @ConditionalOnMissingBean({MapperFactoryBean.class, MapperScannerConfigurer.class})
    public static class MapperScannerRegistrarNotFoundConfiguration implements InitializingBean {
        public MapperScannerRegistrarNotFoundConfiguration() {
        }

        public void afterPropertiesSet() {
            MybatisAutoConfiguration.logger.debug("Not found configuration for registering mapper bean using @MapperScan, MapperFactoryBean and MapperScannerConfigurer.");
        }
    }

很显然这个内部类是一个自动配置了,并且还使用了@Import注解导入了:AutoConfiguredMapperScannerRegistrar这个类,这个类就是自动扫描的核心类,下面进入这个类:

需要注意的是要想使用@Import生效,那么必须要满足上面的条件注解:Spring容器中没有:MapperFactoryBean和MapperScannerConfigurer

进入AutoConfiguredMapperScannerRegistrar这个类:这里我就截取部分源代码:

csharp

代码解读

复制代码

 public static class AutoConfiguredMapperScannerRegistrar implements BeanFactoryAware, EnvironmentAware, ImportBeanDefinitionRegistrar {
        private BeanFactory beanFactory;
        private Environment environment;

        public AutoConfiguredMapperScannerRegistrar() {
        }

        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            if (!AutoConfigurationPackages.has(this.beanFactory)) {
                MybatisAutoConfiguration.logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.");
            } else {
                MybatisAutoConfiguration.logger.debug("Searching for mappers annotated with @Mapper");
                List<String> packages = AutoConfigurationPackages.get(this.beanFactory);
                if (MybatisAutoConfiguration.logger.isDebugEnabled()) {
                    packages.forEach((pkg) -> {
                        MybatisAutoConfiguration.logger.debug("Using auto-configuration base package '{}'", pkg);
                    });
                }

                BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
                builder.addPropertyValue("processPropertyPlaceHolders", true);
                builder.addPropertyValue("annotationClass", Mapper.class);
                builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(packages));
                BeanWrapper beanWrapper = new BeanWrapperImpl(MapperScannerConfigurer.class);

显然这个类实现了:ImportBeanDefinitionRegistrar这个类,那么自然需要重写:registerBeanDefinitions()方法,自然核心逻辑就在这个方法中:

在源码中能够清楚的发现它在构建一个beanDefinition:而构建的类就是:MapperScannerConfigurer

ini

代码解读

复制代码

BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);

并且还对这个beanDefinition添加了一些属性:

vbscript

代码解读

复制代码

                builder.addPropertyValue("annotationClass", Mapper.class);
                builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(packages));

其中比较关键的就是添加了需要扫描的注解为:Mapper注解。

需要扫描的路径为:Springboot扫描bean的路径, 这里并不是直接写死的,而是通过一个工具类获取到的,而这个包路径则是在启动的时候在@SpringBootApplication这个注解的@EnableAutoConfiguration注解的@AutoConfigurationPackage注解中添加进去的。

并且它导入的MapperScannerConfigurer这个类它实现了:BeanDefinitionRegistryPostProcessor这个beanFactoryPostProcessor,那么自然就要重写postProcessBeanDefinitionRegistry()方法,而扫描的逻辑就是在这个方法中实现的,而这个方法的调用就是在Spring启动的Refresh()方法中的:invokeBeanFactoryPostProcessors(beanFactory);方法中。

到这里Springboot整合mybatis实现Mapper接口的自动扫描源码就分析结束了,下面我们看看加了@MapperScan注解的情况。

3.加了@MapperScan注解:

如果项目中加了@MapperScan注解,那么程序员自然就会去配置扫描的路径,而Springboot就会直接去扫描配置的这个路径:

下面我们直接进入@MapperScan()注解:

less

代码解读

复制代码

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
@Repeatable(MapperScans.class)
public @interface MapperScan {

}

发现它也导入了:MapperScannerRegistrar这个类,那么其实现的逻辑跟上面的没有加@MapperScan注解的实现逻辑就是一样的了,只是扫描的包不一样而已。

4.总结:

在项目中使用MapperScan注解和不使用MapperScan注解其实区别不大,只是如果你不适应MapperScan注解的话,那么你需要对你的Mapper接口加上@Mapper注解那么Springboot才能够扫描到,如果你使用了@MapperScan注解的话,那么你只需要配置包路径即可。

注意:如果在项目中如果使用了@MapperScan注解的话,那么Springboot自动帮你扫描的那段逻辑也就是标题的第二点就不会生效了,因为我们看了它的源码,它那个内部类中有一个条件注解,其条件就是容器中不存在:MapperScannerRegistrar的话才会生效,显然当使用@MapperScan的时候也导入了MapperScannerRegistrar所以说容器中已经存在了,那么自动扫描那一套就自然不会生效,从而就不会导致重复扫描的问题了。

到这里不知道有没有一个疑问,就是:如果Springboot在启动的时候,先执行了Srpingboot的自动扫描,然后再执行了@MapperScan注解,这样的话也会导致扫描了两遍。其实不会的,它这里还是有一个优先级的, @MapperScan注解的优先级是大于Springboot的自动扫描。


转载来源:https://juejin.cn/post/7373306258404229129

相关文章
|
22天前
|
数据采集 监控 前端开发
二级公立医院绩效考核系统源码,B/S架构,前后端分别基于Spring Boot和Avue框架
医院绩效管理系统通过与HIS系统的无缝对接,实现数据网络化采集、评价结果透明化管理及奖金分配自动化生成。系统涵盖科室和个人绩效考核、医疗质量考核、数据采集、绩效工资核算、收支核算、工作量统计、单项奖惩等功能,提升绩效评估的全面性、准确性和公正性。技术栈采用B/S架构,前后端分别基于Spring Boot和Avue框架。
|
21天前
|
JavaScript Java 项目管理
Java毕设学习 基于SpringBoot + Vue 的医院管理系统 持续给大家寻找Java毕设学习项目(附源码)
基于SpringBoot + Vue的医院管理系统,涵盖医院、患者、挂号、药物、检查、病床、排班管理和数据分析等功能。开发工具为IDEA和HBuilder X,环境需配置jdk8、Node.js14、MySQL8。文末提供源码下载链接。
|
1月前
|
前端开发 Java Apache
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个
本文详细讲解了如何整合Apache Shiro与Spring Boot项目,包括数据库准备、项目配置、实体类、Mapper、Service、Controller的创建和配置,以及Shiro的配置和使用。
303 1
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个
|
1月前
|
架构师 Java 开发者
得物面试:Springboot自动装配机制是什么?如何控制一个bean 是否加载,使用什么注解?
在40岁老架构师尼恩的读者交流群中,近期多位读者成功获得了知名互联网企业的面试机会,如得物、阿里、滴滴等。然而,面对“Spring Boot自动装配机制”等核心面试题,部分读者因准备不足而未能顺利通过。为此,尼恩团队将系统化梳理和总结这一主题,帮助大家全面提升技术水平,让面试官“爱到不能自已”。
得物面试:Springboot自动装配机制是什么?如何控制一个bean 是否加载,使用什么注解?
|
1月前
|
Java 关系型数据库 MySQL
springboot学习五:springboot整合Mybatis 连接 mysql数据库
这篇文章是关于如何使用Spring Boot整合MyBatis来连接MySQL数据库,并进行基本的增删改查操作的教程。
76 0
springboot学习五:springboot整合Mybatis 连接 mysql数据库
|
1月前
|
Java 数据库连接 API
springBoot:后端解决跨域&Mybatis-Plus&SwaggerUI&代码生成器 (四)
本文介绍了后端解决跨域问题的方法及Mybatis-Plus的配置与使用。首先通过创建`CorsConfig`类并设置相关参数来实现跨域请求处理。接着,详细描述了如何引入Mybatis-Plus插件,包括配置`MybatisPlusConfig`类、定义Mapper接口以及Service层。此外,还展示了如何配置分页查询功能,并引入SwaggerUI进行API文档生成。最后,提供了代码生成器的配置示例,帮助快速生成项目所需的基础代码。
|
1月前
|
机器学习/深度学习 移动开发 自然语言处理
基于人工智能技术的智能导诊系统源码,SpringBoot作为后端服务的框架,提供快速开发,自动配置和生产级特性
当身体不适却不知该挂哪个科室时,智能导诊系统应运而生。患者只需选择不适部位和症状,系统即可迅速推荐正确科室,避免排错队浪费时间。该系统基于SpringBoot、Redis、MyBatis Plus等技术架构,支持多渠道接入,具备自然语言理解和多输入方式,确保高效精准的导诊体验。无论是线上医疗平台还是大型医院,智能导诊系统均能有效优化就诊流程。
|
1月前
|
Java 数据库连接 Maven
Spring整合Mybatis
Spring整合Mybatis
|
1月前
|
Java 数据库连接 Maven
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和MyBatis Generator,使用逆向工程来自动生成Java代码,包括实体类、Mapper文件和Example文件,以提高开发效率。
110 2
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
|
1月前
|
SQL JSON Java
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和PageHelper进行分页操作,并且集成Swagger2来生成API文档,同时定义了统一的数据返回格式和请求模块。
54 1
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块