Spring Boot项目到底是怎么运行的呢?Maven项目,我们一般从pom.xml文件探究起。
如果想年后找到更好的工作,推荐看这篇文章:
Java后端面试复习规划表,5万字
1、pom.xml探究
1.1、父依赖
(1)Spring Boot项目主要依赖的是一个父项目(
spring-boot-starter-parent)。
pom.xml文件:
org.springframework.boot
spring-boot-starter-parent
2.7.7
注:
spring-boot-starter-parent项目的主要作用是:
- 对项目的资源进行过滤。
- spring-boot-starter-parent-2.7.7.pom文件:
${basedir}/src/main/resources
true
**/application*.yml
**/application*.yaml
**/application*.properties
${basedir}/src/main/resources
**/application*.yml
**/application*.yaml
**/application*.properties
- 对项目的插件进行管理。
- spring-boot-starter-parent-2.7.7.pom文件:
org.jetbrains.kotlin
kotlin-maven-plugin
${kotlin.version}
${java.version}
true
compile
compile
compile
test-compile
test-compile
test-compile
org.apache.maven.plugins
maven-compiler-plugin
true
……
(2)点击进入该父项目(
spring-boot-starter-parent),发现它还有一个父项目(spring-boot-dependencies)。
spring-boot-starter-parent-2.7.7.pom文件:
org.springframework.boot
spring-boot-dependencies
2.7.7
spring-boot-dependencies项目才是真正管理SpringBoot应用中所有依赖及其版本的地方。spring-boot-dependencies项目的主要作用是:
- 对SpringBoot项目中依赖的所有jar包的版本进行管理。
- spring-boot-dependencies-2.7.7.pom文件:
5.16.5
2.7.7
1.9.98
3.3.0
1.6
2.11.1
11.5.7.0
1.0.15.RELEASE
4.9.10
2.1.214
5.6.14.Final
6.2.5.Final
2.60.0
4.5.14
5.1.4
4.4.16
5.1.5
1.2.0
1.3.2
1.1.1
1.1.4
1.0
1.6.2
1.1
1.1
1.2.0
2.7.0
2.4.8
1.5.1
1.2
1.3.1
4.13.2
5.8.2
3.1.2
2.17.2
1.2.11
1.18.24
3.2.0
3.10.1
3.3.0
2.8.2
3.2.0
2.5.2
3.2.2
3.2.2
3.4.1
3.2.0
3.3.2
4.6.1
8.0.31
5.14.2
0.5.0
5.3.24
2.8.11
5.7.6
2021.2.0
3.36.0.3
3.0.15.RELEASE
2.0.1
3.0.4.RELEASE
3.0.5.RELEASE
3.0.0
9.0.70
2.10.0
0.50
1.0.2
2.9.0
因此,以后我们导入依赖包时默认是不需要配置版本的;但是如果导入的包没有在依赖中管理,那么就需要我们手动配置版本了。
注:Spring Boot官方文档列出Spring Boot项目中我们可以使用的所有依赖及其默认版本。
1.2、启动器
所谓“启动器”,即:Spring Boot应用依赖的一个个spring-boot-starter-XXX项目。
SpringBoot将所有的功能场景都抽取出来,做成一个个的starter (启动器),我们只需要在项目中引入这些starter即可将所有相关的依赖都导入进来 , 我们要用什么功能就导入什么样的场景启动器即可 ;我们未来也可以自己自定义starter。
如:spring-boot-starter-web启动器:帮我们导入了web模块正常运行所依赖的组件。
pom.xml文件:
org.springframework.boot
spring-boot-starter-web
注:Spring Boot官方文档列出Spring Boot项目中我们可以使用的所有启动器。
2、主启动类运行原理
2.1、默认的主启动类
Springboot01HelloworldApplication.java文件:
package com.atangbiji;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
//@SpringBootApplication用来标注一个主程序类,说明这是一个Spring Boot应用
@SpringBootApplication
public class Springboot01HelloworldApplication {
//SpringBoot应用程序的主入口函数
public static void main(String[] args) {
//以为是启动了一个方法,没想到启动了一个服务
SpringApplication.run(Springboot01HelloworldApplication.class, args);
}
}
但是一个简单的启动类并不简单!主启动类主要通过@SpringBootApplication注解和SpringApplication类调用run方法启动,接下来我们来分析一下它们都干了什么。
注:Spring Boot项目启动后,会像Java应用启动一样,会在后台启动一个几百兆的Java进程。如下图所示:
该进程对应的进程号(PID)通常我们可以在Spring Boot的启动log中查看。如下图所示:
2.2、@SpringBootApplication注解
作用:@SpringBootApplication用来标注一个主程序类,说明这是一个Spring Boot应用。 SpringBoot就通过运行这个类的main方法来启动SpringBoot应用。
点击进入SpringBootApplication注解:可以看到上面还有很多其他注解!
SpringBootApplication.java文件:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
//SpringBoot的配置类
@SpringBootConfiguration
//开启自动配置功能
@EnableAutoConfiguration
//扫描XX包下的组件或者bean
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
// ......
}
2.2.1、@ComponentScan注解
@ComponentScan注解在Spring中很重要,它对应XML配置中的元素。
作用:自动扫描并加载主启动类(
Springboot01HelloworldApplication)同级目录下符合条件的组件或者bean,将这个bean定义加载到IOC容器中。
2.2.2、@SpringBootConfiguration注解
作用:SpringBoot的配置类,标注在某个类上,表示这是一个SpringBoot的配置类。
2.2.2.1、@Configuration注解
点击进入@SpringBootConfiguration注解:可以看到上面还有很多其他注解!
SpringBootConfiguration.java文件:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
//配置类
@Configuration
@Indexed
public @interface SpringBootConfiguration {
// ......
}
这里的@Configuration注解说明:这是一个配置类。配置类就对应Spring的xml配置文件。
2.2.2.2、@Component注解
点击进入@Configuration注解:可以看到它也是一个组件(Component)!
Configuration.java文件:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
//组件(Bean)
@Component
public @interface Configuration {
// ......
}
这里的@Component注解说明:主启动类本身也是Spring中的一个组件(Bean)而已,负责启动Spring Boot应用!
接下来,我们回到SpringBootApplication注解中继续分析。
2.2.3、@EnableAutoConfiguration注解(重点)
作用:开启自动配置功能。
以前我们需要自己手动配置的东西,而现在SpringBoot可以自动帮我们配置 ;通过@EnableAutoConfiguration注解让SpringBoot开启自动配置功能后,自动配置才能生效。
2.2.3.1、@AutoConfigurationPackage注解
(1)点击进入@EnableAutoConfiguration注解:可以看到它包含一个@AutoConfigurationPackage注解。
EnableAutoConfiguration.java文件:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
//自动配置包
@AutoConfigurationPackage
//(向IOC容器中)导入自动配置导入选择器
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
// ......
}
这里的@AutoConfigurationPackage注解的作用是:自动配置包。
(2)点击进入@AutoConfigurationPackage注解:可以看到它通过@Import(
AutoConfigurationPackages.Registrar.class)注解向容器中导入“自动配置包注册器”组件。
AutoConfigurationPackage.java文件:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
//向容器中导入“自动配置包注册器”组件(Bean)
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
// ......
}
注:
- 这里的@import注解是Spring的底层注解,它的作用是:向容器中导入组件(Bean)。
- 这里的Registrar.class的作用是:将主启动类的所在包及包下面所有子包里面的所有组件扫描到Spring IOC容器中。
接下来,返回上一级,我们回到EnableAutoConfiguration注解中继续分析。
2.2.3.2、通过@Import注解导入自动配置导入选择器
点击进入@EnableAutoConfiguration注解:可以看到它通过@Import({
AutoConfigurationImportSelector.class})注解,向IOC容器中导入自动配置导入选择器(
AutoConfigurationImportSelector)组件(Bean)。
自动配置导入选择器会导入哪些组件的选择器呢?
(1)点击进入
AutoConfigurationImportSelector类,可以发现:这个类中有一个
getCandidateConfigurations方法。
AutoConfigurationImportSelector.java文件:
//获取候选的配置
protected List getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List configurations = new ArrayList<>(
SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()));
//导入候选的配置
ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()).forEach(configurations::add);
Assert.notEmpty(configurations,
"No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}
注:
- getCandidateConfigurations方法的作用是:获取候选的配置。
- 该方法通过调用ImportCandidates的load方法导入候选的配置!
(2)点击进入ImportCandidates类的load()方法,可以发现:其中加载了本地META-INF/spring目录下的自动配置核心文件(即
org.springframework.boot.autoconfigure.AutoConfiguration.imports文件)。
ImportCandidates.java文件:
//自动配置核心文件的本地目录
private static final String LOCATION = "META-INF/spring/%s.imports";
//导入候选的配置
public static ImportCandidates load(Class> annotation, ClassLoader classLoader) {
Assert.notNull(annotation, "'annotation' must not be null");
ClassLoader classLoaderToUse = decideClassloader(classLoader);
//加载本地的自动配置核心文件
String location = String.format(LOCATION, annotation.getName());
Enumeration urls = findUrlsInClasspath(classLoaderToUse, location);
List importCandidates = new ArrayList<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
importCandidates.addAll(readCandidateConfigurations(url));
}
return new ImportCandidates(importCandidates);
}
(3)查看Spring Boot自动配置的核心文件。
org.springframework.boot.autoconfigure.AutoConfiguration.imports文件是Spring Boot自动配置的核心文件。它位于
spring-boot-autoconfigure-2.7.7.jar包的META-INF/spring目录下,如下图所示:
注:
- Spring Boot自动配置的核心文件中的所有类(Beans)都是通过java配置类的方式显式地配置到Spring IOC容器中的。
- Spring Boot自动配置的核心文件中没有的类(Beans)都需要我们手动进行配置。
(4)我们在自动配置的核心文件中随便找一个自动配置类进行全局搜索,如:WebMvcAutoConfiguration。
可以发现:这些类的都是JavaConfig配置类,而且都注入了一些Bean。我们可以找一些自己认识的自动配置类,看着熟悉一下!
所以,自动配置真正实现是从classpath中搜寻所有META-INF/spring/目录下的
org.springframework.boot.autoconfigure.AutoConfiguration.imports配置文件,并将其中对应的配置项,通过反射实例化为自动配置类,然后将这些都汇总成为一个实例并加载到Spring IOC容器中。
2.2.3.3、结论
(1)SpringBoot所有的自动配置都是在主启动类启动时扫描并加载的。
(2)SpringBoot自动配置好的这些组件(Bean),需要我们导入对应的启动器(spring-boot-starter-XXX)后才会生效。即:只有@ConditionalOnXXX注解中的条件都满足时,自动配置的相应组件(Bean)才会生效。
(3)SpringBoot在启动的时候,从类路径(classpath)的META-INF/spring目录下的
org.springframework.boot.autoconfigure.AutoConfiguration.imports配置文件中获取值。
(4)SpringBoot将这些值作为自动配置类导入Spring IOC容器,自动配置类就生效,帮我们进行自动配置工作。
(5)整个J2EE的整体解决方案和自动配置都在spring-boot-autoconfigure的jar包中。
(6)SpringBoot会向容器中导入非常多的自动配置类(xxxAutoConfiguration),就是向容器中导入这个场景需要的所有组件,并配置好这些组件。
(7)有了自动配置类,免去了我们手动编写配置注入功能组件等工作。
2.3、SpringApplication类
2.3.1、SpringApplication类的作用
SpringApplication类主要完成以下四件事情:
- 推断应用的类型是普通的项目还是Web项目。
- 查找并加载所有可用初始化器,并设置到initializers(初始化)属性中。
- 找出所有的应用程序监听器,设置到listeners属性中。
- 推断并设main方法的定义类,找到运行的主类。
好了,今天就分享到这里,如果有点点帮助,记得点赞、收藏、分享,谢啦!