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

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 该文档详细介绍了如何在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

相关文章
|
1月前
|
数据采集 监控 前端开发
二级公立医院绩效考核系统源码,B/S架构,前后端分别基于Spring Boot和Avue框架
医院绩效管理系统通过与HIS系统的无缝对接,实现数据网络化采集、评价结果透明化管理及奖金分配自动化生成。系统涵盖科室和个人绩效考核、医疗质量考核、数据采集、绩效工资核算、收支核算、工作量统计、单项奖惩等功能,提升绩效评估的全面性、准确性和公正性。技术栈采用B/S架构,前后端分别基于Spring Boot和Avue框架。
|
2天前
|
Java 数据库连接 Maven
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
自动装配是现在面试中常考的一道面试题。本文基于最新的 SpringBoot 3.3.3 版本的源码来分析自动装配的原理,并在文未说明了SpringBoot2和SpringBoot3的自动装配源码中区别,以及面试回答的拿分核心话术。
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
|
2天前
|
Java Maven Spring
SpringBoot配置跨模块扫描问题解决方案
在分布式项目中,使用Maven进行多模块开发时,某些模块(如xxx-common)没有启动类。如何将这些模块中的类注册为Spring管理的Bean对象?本文通过案例分析,介绍了两种解决方案:常规方案是通过`@SpringBootApplication(scanBasePackages)`指定扫描路径;推荐方案是保持各模块包结构一致(如com.xxx),利用SpringBoot默认扫描规则自动识别其他模块中的组件,简化配置。
SpringBoot配置跨模块扫描问题解决方案
|
12天前
|
存储 JavaScript 前端开发
基于 SpringBoot 和 Vue 开发校园点餐订餐外卖跑腿Java源码
一个非常实用的校园外卖系统,基于 SpringBoot 和 Vue 的开发。这一系统源于黑马的外卖案例项目 经过站长的进一步改进和优化,提供了更丰富的功能和更高的可用性。 这个项目的架构设计非常有趣。虽然它采用了SpringBoot和Vue的组合,但并不是一个完全分离的项目。 前端视图通过JS的方式引入了Vue和Element UI,既能利用Vue的快速开发优势,
69 13
|
20天前
|
JavaScript 安全 Java
java版药品不良反应智能监测系统源码,采用SpringBoot、Vue、MySQL技术开发
基于B/S架构,采用Java、SpringBoot、Vue、MySQL等技术自主研发的ADR智能监测系统,适用于三甲医院,支持二次开发。该系统能自动监测全院患者药物不良反应,通过移动端和PC端实时反馈,提升用药安全。系统涵盖规则管理、监测报告、系统管理三大模块,确保精准、高效地处理ADR事件。
|
25天前
|
缓存 Java 数据库连接
深入探讨:Spring与MyBatis中的连接池与缓存机制
Spring 与 MyBatis 提供了强大的连接池和缓存机制,通过合理配置和使用这些机制,可以显著提升应用的性能和可扩展性。连接池通过复用数据库连接减少了连接创建和销毁的开销,而 MyBatis 的一级缓存和二级缓存则通过缓存查询结果减少了数据库访问次数。在实际应用中,结合具体的业务需求和系统架构,优化连接池和缓存的配置,是提升系统性能的重要手段。
40 4
|
25天前
|
SQL Java 数据库连接
spring和Mybatis的各种查询
Spring 和 MyBatis 的结合使得数据访问层的开发变得更加简洁和高效。通过以上各种查询操作的详细讲解,我们可以看到 MyBatis 在处理简单查询、条件查询、分页查询、联合查询和动态 SQL 查询方面的强大功能。熟练掌握这些操作,可以极大提升开发效率和代码质量。
38 3
|
1月前
|
Java 数据库连接 数据库
spring和Mybatis的逆向工程
通过本文的介绍,我们了解了如何使用Spring和MyBatis进行逆向工程,包括环境配置、MyBatis Generator配置、Spring和MyBatis整合以及业务逻辑的编写。逆向工程极大地提高了开发效率,减少了重复劳动,保证了代码的一致性和可维护性。希望这篇文章能帮助你在项目中高效地使用Spring和MyBatis。
23 1
|
2月前
|
SQL JSON Java
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和PageHelper进行分页操作,并且集成Swagger2来生成API文档,同时定义了统一的数据返回格式和请求模块。
78 1
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
|
1月前
|
JavaScript Java 项目管理
Java毕设学习 基于SpringBoot + Vue 的医院管理系统 持续给大家寻找Java毕设学习项目(附源码)
基于SpringBoot + Vue的医院管理系统,涵盖医院、患者、挂号、药物、检查、病床、排班管理和数据分析等功能。开发工具为IDEA和HBuilder X,环境需配置jdk8、Node.js14、MySQL8。文末提供源码下载链接。