赞
踩
在Java领域,主流的web开发莫过于spring boot了。大家都知道spring boot是一个快速整合spring生态的脚手架,那么,你真的了解spring boot的底层原理吗?都说spring boot是约定大于配置的,那么为什么要这样设置,本篇文章就来了解一下spring boot的自动配置原理。让你了解一下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注解是由三个主要的注解构成的:
就是这三个注解撑起了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博客
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。