前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >SpringBoot自动装配原理笔记

SpringBoot自动装配原理笔记

原创
作者头像
Java鱼头
发布于 2022-11-29 13:57:59
发布于 2022-11-29 13:57:59
82110
代码可运行
举报
文章被收录于专栏:Java-docJava-doc
运行总次数:0
代码可运行

理论介绍

SpringBoot通过自动装配实现了第三方框架系统对象的注入。这种实现机制和我们前面介绍的SPI(服务扩展机制)很相似。

源码分析

Spring的IoC

SpringBoot的本质是SpringFramework【IoC,AOP】的再次封装的上层应用框架。

run方法

我们启动一个SpringBoot项目,本质上就是执行了启动类中的主方法,然后调用执行了run方法,那么run方法到底做了什么操作呢?我们可以先来分析下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@SpringBootApplication
@MapperScan("com.xx.mapper")
public class SpringBootVipDemoApplication {
    public static void main(String[] args) {
        // 基于配置文件的方式
        ApplicationContext ac1 = new ClassPathXmlApplicationContext("");
        // 基于Java配置类的方式
        ApplicationContext ac2 = new AnnotationConfigApplicationContext(SpringBootVipDemoApplication.class);
		// run 方法的返回对象是 ConfigurableApplicationContext 对象
        ConfigurableApplicationContext ac3 = SpringApplication.run(SpringBootVipDemoApplication.class, args);
    }
}

ConfigurableApplicationContext这个对象其实是 ApplicationContext接口的一个子接口

那么上面的代码可以调整为

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@SpringBootApplication
@MapperScan("com.xx.mapper")
public class SpringBootVipDemoApplication {

    public static void main(String[] args) {
        // 基于配置文件的方式
        ApplicationContext ac1 = new ClassPathXmlApplicationContext("");
        // 基于Java配置类的方式
        ApplicationContext ac2 = new AnnotationConfigApplicationContext(SpringBootVipDemoApplication.class);
        // run 方法执行完成后返回的是一个 ApplicationContext 对象
        // 到这儿我们是不是可以猜测 run 方法的执行 其实就是Spring的初始化操作[IoC]
        ApplicationContext ac3 = SpringApplication.run(SpringBootVipDemoApplication.class, args);
    }

}

根据返回结果,我们猜测SpringBoot项目的启动其实就是Spring的初始化操作【IoC】。

下一步:

下一步:

直接调用:

到这儿,其实我们就可以发现SpringBoot项目的启动,本质上就是Spring的初始化操作。但是并没有涉及到SpringBoot的核心装配。

@SpringBootApplication

@SpringBootApplication点开后我们能够发现@SpringBootApplication这个注解其实是一个组合注解

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)

我们发现@SpringBootApplication注解的前面四个注解是JDK中自动的元注解 (用来修饰注解的注解)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Target({ElementType.TYPE}) // 表明 修饰的注解的位置 TYPE 表示只能修饰类
@Retention(RetentionPolicy.RUNTIME) // 表明注解的作用域
@Documented // API 文档抽取的时候会将该注解 抽取到API文档中
@Inherited  // 表示注解的继承

还有就是@ComponentScan注解,该注解的作用是用来指定扫描路径的,如果不指定特定的扫描路径的话,扫描的路径是当前修饰的类所在的包及其子包。

@SpringBootConfiguration这个注解的本质其实是@Configuration注解。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
// 上面是3个元注解
// @Configuration 注解修饰的Java类是一个配置类
@Configuration
// @Indexed
@Indexed
public @interface SpringBootConfiguration {
    @AliasFor(
        annotation = Configuration.class
    )
    boolean proxyBeanMethods() default true;
}

这样一来7个注解,咱们清楚了其中的6个注解的作用,而且这6个注解都和SpringBoot的自动装配是没有关系的。

@EnableAutoConfiguration

@EnableAutoConfiguration这个注解就是SpringBoot自动装配的关键。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
​
    Class<?>[] exclude() default {};
​
    String[] excludeName() default {};
}

我们发现要搞清楚EnableAutoConfiguration注解的关键是要弄清楚@Import注解。这个内容我们前面在注解编程发展中有详细的介绍。AutoConfigurationImportSelector实现了ImportSelector接口,那么我们清楚只需要关注selectImports方法的返回结果即可

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
            // 返回的就是需要注册到IoC容器中的对象对应的类型的全类路径名称的字符串数组
            // ["com.bobo.pojo.User","com.bobo.pojo.Person", ....]
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    }

我们清楚了该方法的作用就是要返回需要注册到IoC容器中的对象对应的类型的全类路径名称的字符串数组。那么我接下来分析的关键是返回的数据是哪来的?所以呢进入getAutoConfigurationEntry方法中。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        } else {
            // 获取注解的属性信息
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            // 获取候选配置信息 加载的是 当前项目的classpath目录下的 所有的 spring.factories 文件中的 key 为
            // org.springframework.boot.autoconfigure.EnableAutoConfiguration 的信息
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            configurations = this.removeDuplicates(configurations);
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
            this.checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = this.getConfigurationClassFilter().filter(configurations);
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }

先不进入代码,直接DEBUG调试到 候选配置信息这步。我们发现里面有很多个Java类。

然后进入getCandidateConfiguration方法中,我们可以发现加载的是 META-INF/spring.factories 文件中的配置信息

然后我们可以验证,进入到具体的META-INF目录下查看文件。

最后几个

在我们的Debug中还有一个配置文件(MyBatisAutoConfiguration)是哪来的呢?

深入源码也可以看到真正加载的文件

然后我们继续往下看源码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        } else {
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            // 因为会加载多个 spring.factories 文件,那么就有可能存在同名的,
            // removeDuplicates方法的作用是 移除同名的
            configurations = this.removeDuplicates(configurations);
            // 获取我们配置的 exclude 信息
            // @SpringBootApplication(exclude = {RabbitAutoConfiguration.class})
            // 显示的指定不要加载那个配置类
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
            this.checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            // filter的作用是 过滤掉咱们不需要使用的配置类。
            configurations = this.getConfigurationClassFilter().filter(configurations);
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }

先来看过滤的效果:

那么我们需要考虑这个过滤到底是怎么实现的呢?进入filter方法

我们可以看到有具体的匹配方法 match。里面有个关键的属性是 autoConfigurationMetadata,的本质是 加载的 META-INF/spring-autoconfigure-metadata.properties 的文件中的内容。我们以 RedisAutoConfiguration 为例:

通过上面的配置文件,我们发现RedisAutoConfiguration 被注入到IoC中的条件是系统中要存在 org.springframework.data.redis.core.RedisOperations 这个class文件。首先系统中不存在 RedisOperations 这个class文件。

过滤后,我们发现 RedisAutoConfiguration 就不存在了。

但是当我们在系统中显示的创建 RedisOperations Java类后,filter就不会过滤 RedisAutoConfiguration 配置文件了。

到这其实我们就已经给大家介绍完了SpringBoot的自动装配原理。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
1 条评论
热度
最新
关注【Java面试教程】,发送mmmjava获取笔记
关注【Java面试教程】,发送mmmjava获取笔记
回复回复点赞举报
推荐阅读
SpringBoot 注解原理,自动装配原理,图文并茂,万字长文!
点进@SpringBootApplication来看,发现@SpringBootApplication是一个组合注解。
搜云库技术团队
2020/06/17
1.8K0
SpringBoot 注解原理,自动装配原理,图文并茂,万字长文!
SpringBoot自动装配原理解析
我们知道,在使用SpringBoot的时候,我们只需要如下方式即可直接启动一个Web程序:
Java学习录
2019/09/23
1.4K0
SpringBoot自动装配原理解析
【SpringBoot】自动配置
自动配置是SpringBoot框架中的核心之一,其目的是将我们开发中引入的jar包类和自己编写的业务类自动注入到IoC容器中,而无需像我们的Spring一样,需要在配置文件中进行繁杂冗余的配置。例如我们使用事务时,在SpringBoot中无需任何操作,只要我们在配置文件中简单配置一下数据源即可,像事务管理器等内容SpringBoot框架已经我们注册成为Bean了;在Spring中,我们还需要在配置文件中引入事务管理器、数据库连接池、数据源等内容。
用户11182874
2025/01/19
1120
【SpringBoot】自动配置
程序员必备技能之SpringBoot的自动装配原理,很详细,建议收藏!!!
  SpringBoot应该是每个Java程序猿都会使用的基础框架了,对于SpringBoot的核心内容自动装配原理的掌握就显得非常重要了。
用户4919348
2021/07/29
5720
程序员必备技能之SpringBoot的自动装配原理,很详细,建议收藏!!!
SpringBoot自动装配的原理
自动装配是SpringBoot的核心,从Spring的起源来说,一开始是通过XML文件对Bean进行装载,后来使用JavaConfig的方式实现无配置化的解决方案,但是本质问题并没有得到解决,直到SpringBoot的问世,帮开发者省略了繁琐的基础性的工作,是开发者更加关注于逻辑本身,SpringBoot将繁琐的基础性工作交给了Starter组件和自动装配去做。
NorthS
2023/03/21
7050
SpringBoot自动装配的原理
SpringBoot开篇
SpringBoot 前言: SpringBoot是一个服务于Spring框架的框架,用来简化对于bean的获取, 快速构建一个web服务, 它的基础依然是Spring。 在SpringBoot还未出来以前使用的最多的架构体系可能是SpringMVC + Mybatis or Spring + Struts2 +Hibernate ,甚至是最早期的JSP + Servlet. 以上框架搭建起来过于繁琐,而且需要进行大量的配置,每次搭建一个web项目可能会遇到各种各样的问题,所以一般公司都会生成相应的
用户1215919
2021/12/28
1870
springboot自动装配原理
使用springboot的过程中我们发现,框架层帮我们自动注册了很多能力,类似的基础配置、集成能力支撑等,我们之前有分析过springboot应用启动的时候自动扫描注册的bean要么是启动门面类路径及子路径下的信息,要么就是用户指定的路径信息,springboot所支持的部件和框架层配置肯定不在我们指定的路径下,按照这个思路应用启动时并不会把相应的配置实例化到上下文中,而我们编写的所有业务代码甚至扩展框架信息都是基于框架能力的支撑,没有这些配置和基础组件是不可能实现的,我们本篇就围绕springboot自动装配展开分析。
叔牙
2022/01/20
1.3K0
springboot自动装配原理
手撸一个自定义starter,它不香吗
springboot 中有很多的starter 。我们用起来很爽不是吗,之所以这么爽难道不是因为我们少了很多配置吗,之前我们想要使用jdbcTemplete 是不是需要在xml 文件中配置bean 后才能使用。有被xml 一堆配置支配的恐惧吗?
程序员爱酸奶
2020/05/22
1.1K0
SpringBoot 自动装配原理,看不懂不存在的
🍁 作者:知识浅谈,CSDN签约讲师,CSDN原力作者,后端领域优质创作者,热爱分享,热爱创作 📌 擅长领域:后端全栈工程师、爬虫、ACM算法 面试官常问的问题: 什么是 SpringBoot 自动装配? SpringBoot 是如何实现自动装配的?如何实现按需加载? 🤞这次都给他拿下🤞 为什么 Spring Boot 使用起来这么酸爽呢? 这得益于其自动装配。 正菜来了🛴🛴🛴 🍖什么是 SpringBoot 自动装配? 我们现在提到自动装配的时候,一般会和 Spring Boot 联系在一起。但是,
知识浅谈
2022/07/12
8521
SpringBoot 自动装配原理,看不懂不存在的
Spring Boot 系列二:SpringBoot自动配置原理
学长在这里想对小伙伴们提问一个问题:你们有对SpringBoot自动配置原理进行了解吗?今天学长来带领大家学习Spring Boot 自动配置原理~~
叶秋学长
2022/08/01
3670
Spring Boot 系列二:SpringBoot自动配置原理
SpringBoot 自动装配的原理分析
关于 SpringBoot 的自动装配功能,相信是每一个 Java 程序员天天都会用到的一个功能,但是它究竟是如何实现的呢?今天阿粉来带大家看一下。
Java极客技术
2022/12/04
2850
SpringBoot 自动装配的原理分析
SpringBoot自动装配探索
SpringBoot自动装配探索 首先看SpringBoot的启动类 @SpringBootApplication public class Application { public static void main(String[] args) { // Customize the spring config location System.setProperty("spring.config.additional-location", "
晓果冻
2022/09/08
3180
SpringBoot自动装配探索
SpringBoot自动装配原理
这里先看自动装配,extends SpringBootServletInitializer这块下一步再探讨
西柚dzh
2022/06/09
3490
SpringBoot自动装配原理
用了那么久的springboot,你知道它的自动装配原理吗?
在使用springboot时,很多配置我们都没有做,都是springboot在帮我们完成,这很大一部分归功于springboot自动装配,那springboot的自动装配的原理是怎么实现的呢?
索码理
2022/09/20
3950
用了那么久的springboot,你知道它的自动装配原理吗?
今天,我们来详细的聊一聊SpringBoot自动配置原理,学了这么久,你学废了吗?
前言什么的,就不说了,大家都会用的,我们直接从 SpringBoot 启动类说起。
宁在春
2022/10/31
4910
今天,我们来详细的聊一聊SpringBoot自动配置原理,学了这么久,你学废了吗?
SpringBoot是如何实现自动装配的
SpringBoot作为当前最火的java开发框架,它的自动装配帮助我们省略了许多繁琐配置,能够帮助我们快速构建一个项目,那么今天我们就一起分析下SpringBoot实现自动装配的原理。
Java进阶之路
2022/08/03
7650
SpringBoot是如何实现自动装配的
SpringBoot - 自动装配 源码解析
主要的功能:进行扫描具有META-INF/spring.factories文件的jar包
小小工匠
2022/04/14
6650
SpringBoot - 自动装配 源码解析
【框架源码】SpringBoot核心源码解读之自动配置源码分析
SpringBoot流行之前,程序员大多是用SSM框架整合来进行WEB后端开发。这种方式非常麻烦,需要手动引入大量的包,还要配置很多XML文件,光是搭建环境就需要很久。
互联网小阿祥
2023/05/28
4670
【框架源码】SpringBoot核心源码解读之自动配置源码分析
第05天 SpringBoot自动配置原理
自从有了 SpringBoot 之后,咋们就起飞了!各种零配置开箱即用,而我们之所以开发起来能够这么爽,自动配置的功劳少不了,今天我们就一起来讨论一下 SpringBoot 自动配置原理。
程序员Leo
2023/08/16
4820
第05天 SpringBoot自动配置原理
一文吃透@SpringbootApplication的前世与今生
SpringBootApplication是标注在启动类上的复合注解,是springboot启动加载IOC容器的核心实现,也是springboot能够实现自动装配的关键逻辑,无论是面试还是自我提升都是必不可少的知识点。
柏炎
2022/08/23
3450
相关推荐
SpringBoot 注解原理,自动装配原理,图文并茂,万字长文!
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文