springboot3的自动装配原理

1、介绍

在Java领域,主流的web开发莫过于spring boot了。大家都知道spring boot是一个快速整合spring生态的脚手架,那么,你真的了解spring boot的底层原理吗?都说spring boot是约定大于配置的,那么为什么要这样设置,本篇文章就来了解一下spring boot的自动配置原理。让你了解一下spring boot是如何启动工作的。

2、spring boot自动装配的解析

(本次我使用到的版本是spring boot3.0.10,如果你使用的是spring boot2.x版本那么可能与我写的会有一些差异。)

使用过spring boot的小伙伴都知道,spring boot的启动是从一个main函数开始的。每个spring boot项目都有一个启动类,这个启动类中有一个main函数,只要运行这个main函数,那么就可以启动我们的springboot项目了。并且这个启动类是放在项目的顶包下的。

@SpringBootApplication
public class MainApplication {

    public static void main(String[] args) {
        SpringApplication.run(MainApplication.class, args);
    }

}

可以看到,这个启动类关键的就两个东西:
 

@SpringBootApplication
SpringApplication.run

一个关键的注解@SpringBootApplication,一个方法SpringApplication.run(),方法中传入了主启动类。

我们先来解析@SpringBootApplication注解。点进这个注解,你会发现它是一个组合注解。不考虑那些元注解。其实这个@SpringBootApplication注解是由三个主要的注解构成的:

  • @SpringBootConfiguration
  • @EnableAutoConfiguration
  • @ComponentScan

就是这三个注解撑起了spring boot的应用,我们接下来一一的解析:

@SpringBootConfiguration

这个注解就是一个配置类注解,表明我们的主启动类也是一个配置类;

点进这个注解就会发现,它包含@Configuration。这个注解在哪个类上,就表示当前这个类是一个配置类。

@EnableAutoConfiguration

这个注解是spring boot开启自动配置的功能的主要注解。我们点进去会发现这个注解包含了两个注解:
@AutoConfigurationPackage

@Import({AutoConfigurationImportSelector.class})

我们接下来来重点看一下这两个注解:
@AutoConfigurationPackage

它主要用于自动配置和管理Spring Boot应用的包结构。

让springboot去扫描默认的配置类,如果没有这个类的话,springboot只会默认扫描启动类下包中各个类的注解

@AutoConfigurationPackage注解的主要作用是将添加该注解的类所在的包(package)作为自动配置的包(package)进行管理。这意味着Spring Boot会自动扫描并配置这个包及其子包下的组,这样就可以确保 Spring Boot 能够发现应用程序中的所有组件,并对它们进行适当的自动配置。

这也就是为什么我们在创建springboot项目时,主启动类会在项目的顶包下了,这样才能保证我们接下来的所有操作(注入容器中的bean)都能被正确的扫描

@Import({AutoConfigurationImportSelector.class})

这个注解的作用就非常大了。它是spring boot之所以能整合各个技术的关键。

我们都知道@Import注解可以将其他配置类中定义的 Bean 或者组件引入到当前配置类中,从而实现模块化的配置。简单的用法是直接导入一个类@Import({ServiceImplA.class}),像这样就可以将一个类或bean导入到当前的配置类中。

但是我们要导入的内容非常多呢,我们也可以使用@Import的批量导入方式;如下所示:
 

public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata metadata) {
        return new String[] {ConfigA.class.getName(), ConfigB.class.getName(), ConfigC.class.getName()};
    }
}

@Configuration
@Import(MyImportSelector.class)
public class AppConfig {
   // 配置类的内容
}

而@Import({AutoConfigurationImportSelector.class})注解也正是一个批量导入的注解。我们点进AutoConfigurationImportSelector.class中可以看到:
1、AutoConfigurationImportSelector这个类里面有一个方法selectImports(),如下

2、在selectImport()方法里调用了一个getAutoConfigurationEntry()方法,

selectImports 方法是 ImportSelector 接口中的一个方法,用于返回需要导入的类的全限定类名数组。在 Spring 容器启动时,Spring 会扫描所有实现了 ImportSelector 接口的类,并调用其中的 selectImports 方法来确定需要导入的类。这个方法里面又调用了一个getCandidateConfigurations()方法

3、在getCandidateConfigurations()方法里面判断最终要自动注入到容器中的bean

使用Assert.notEmpty断言,判断configurations不能为空 ,如果为空了,给你一段提示:没有自动配置的类找到,在

META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

找到,我们将这端配置简称为 .imports 文件,意思就是说,我要去找自动配置类 去 .imports中找,但是我并没有找到。

其实这就是spring boot的约定。所有要第三方技术要自动注入到容器中的bean,将你们要注入的bean放在

META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

文件中。注意,这里只要第三方将要注入的bean放在.import文件中。这个bean数目是非常庞大的,但是有一些bean需要满足一些特定的条件才会被注入到容器中。这时会使用@Condition注解或衍生注解来判断bean是否创建。当然这个过程是那些第三放jar中要进行判断的,对于spring boot来说,只需要在使用时导入相应的jar包,如spring-boot-starter-xxx。导入jar包之后,在spring boot项目启动时,会自动扫描引入jar包下的

META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

文件,将其中需要自动注入到容器中的bean注入容器。当然,在注入bean的过程中肯定会有一些判断bean是否创建。

如:在项目中引入spring-boot-autoconfigure的依赖之后,可以找一个这个jar包的

META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

文件,

这个文件其实就是配置了一堆类的全类名,这些类都是自动配置类。

这些自动配置类需要生效都还要满足不同的需要。

以我们经常使用的web来搜索一下。

可以看到搜索到了一个自动配置类。我们点进去这个自动配置类:

可以看到这个自动配置类上面加了一个条件判断的注解:

@ConditionalOnClass它的这里的意思是,如果你环境里面有DispatcherServlet,那自动配置类就会生效自动注入一个DispatcherServlet的bean对象,如果环境里没有DispatcherServlet,那就不生效,不注入了。

@ComponentScan

这个注解很常见,它允许 Spring 容器在启动的时候自动扫描并发现@Component@Service@Repository@Controller等注解标注的类,并将它们注册为 Spring 容器管理的 bean。如果不指定扫描路径,会默认扫描声明了这个注解的类所在的包及其子包。

SpringApplication.run

这个方法负责创建和初始化Spring应用上下文,并启动整个Spring Boot应用。

你点击这个静态方法可以看到,它创建了一个spring应用上下文,负责管理bean的生命周期。之后加载配置文件如application.yml。通过这些配置文件来初始化项目、自动配置、扫描并注册bean等等

在SpringBoot2.7版本以前,它自动配置使用的配置文件是 spring.factories,它会从 spring.factories配置文件中读取配置类的全类名,那么在SpringBoot2.7以后到3.0以前,它同时兼容了.imports配置文件以及spring.factories配置文件,在3.0以后只支持.imports配置文件,这个大家要清楚。

通过源码分析,我们知道了,SpringBoot自动配置无非就是提供一个自动配置类,把这个类名写到指定的配置文件中就可以了。

在主启动类上添加了SpringBootApplication注解,这个注解组合了EnableAutoConfiguration注解。这个注解中组合了@Import注解,批量导入了AutoConfigurationImportSelector类,这个类实现selectImports方法,经过层层调用,最终会读取

META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

文件(这个文件位置和名称是spring boot官方定义的,不同的版本可能读取的文件不同)读取到全类名后,会解析注解条件,即@Conditional注解及其衍生注解。并把符合条件的bean注册进IOC容器中。

以上就是spring boot自动装配的全流程,其实只是定义了一种规范而已。但是只要遵守这个规范,那么我们编写代码的复杂度就会大大减少。这也就是我们经常说的“约定大于配置大于编码”

那么,我们现在已经知道了这种约定规则了。我们可不可以自定义一个starter。使spring boot项目只要引入了相应的jar包,就可以将一些使用到的bean自动注入IOC容器中。

可以参考一下这篇文章:
springboot3自定义starter(详细入门)-CSDN博客

  • 21
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张乔24

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值