百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

Spring Boot 运行原理(5分钟速解)

csdh11 2025-04-26 17:32 6 浏览

Spring Boot项目到底是怎么运行的呢?Maven项目,我们一般从pom.xml文件探究起。

如果想年后找到更好的工作,推荐看这篇文章

Java后端面试复习规划表,5万字

1、pom.xml探究

1.1、父依赖

(1)Spring Boot项目主要依赖的是一个父项目(
spring-boot-starter-parent
)。

pom.xml文件:

<!-- 父项目 -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.7</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

注:
spring-boot-starter-parent
项目的主要作用是:

  • 对项目的资源进行过滤。
  • spring-boot-starter-parent-2.7.7.pom文件:
  <!-- 资源过滤 -->
  <resources>
      <resource>
          <directory>${basedir}/src/main/resources</directory>
          <filtering>true</filtering>
          <includes>
              <include>**/application*.yml</include>
              <include>**/application*.yaml</include>
              <include>**/application*.properties</include>
          </includes>
      </resource>
      <resource>
          <directory>${basedir}/src/main/resources</directory>
          <excludes>
              <exclude>**/application*.yml</exclude>
              <exclude>**/application*.yaml</exclude>
              <exclude>**/application*.properties</exclude>
          </excludes>
      </resource>
  </resources>
  • 对项目的插件进行管理。
  • spring-boot-starter-parent-2.7.7.pom文件:
  <!-- 插件管理(部分) -->
  <pluginManagement>
        <plugins>
          <plugin>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-maven-plugin</artifactId>
            <version>${kotlin.version}</version>
            <configuration>
              <jvmTarget>${java.version}</jvmTarget>
              <javaParameters>true</javaParameters>
            </configuration>
            <executions>
              <execution>
                <id>compile</id>
                <phase>compile</phase>
                <goals>
                  <goal>compile</goal>
                </goals>
              </execution>
              <execution>
                <id>test-compile</id>
                <phase>test-compile</phase>
                <goals>
                  <goal>test-compile</goal>
                </goals>
              </execution>
            </executions>
          </plugin>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
              <parameters>true</parameters>
            </configuration>
          </plugin>
          ……        
        </plugins>
      </pluginManagement>

(2)点击进入该父项目(
spring-boot-starter-parent
),发现它还有一个父项目(spring-boot-dependencies)。


spring-boot-starter-parent-2.7.7.pom
文件:

<!-- 父项目的父项目 -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.7.7</version>
</parent>

spring-boot-dependencies项目才是真正管理SpringBoot应用中所有依赖及其版本的地方。spring-boot-dependencies项目的主要作用是:

  • SpringBoot项目中依赖的所有jar包的版本进行管理。
  • spring-boot-dependencies-2.7.7.pom文件:
  <!-- 依赖包版本管理(部分) -->
  <properties>
      <activemq.version>5.16.5</activemq.version>
      <antlr2.version>2.7.7</antlr2.version>
      <appengine-sdk.version>1.9.98</appengine-sdk.version>    
      <build-helper-maven-plugin.version>3.3.0</build-helper-maven-plugin.version>    
      <commons-pool.version>1.6</commons-pool.version>
      <commons-pool2.version>2.11.1</commons-pool2.version>
      <db2-jdbc.version>11.5.7.0</db2-jdbc.version>
      <dependency-management-plugin.version>1.0.15.RELEASE</dependency-management-plugin.version>    
      <git-commit-id-plugin.version>4.9.10</git-commit-id-plugin.version>    
      <h2.version>2.1.214</h2.version>    
      <hibernate.version>5.6.14.Final</hibernate.version>
      <hibernate-validator.version>6.2.5.Final</hibernate-validator.version>    
      <htmlunit.version>2.60.0</htmlunit.version>
      <httpclient.version>4.5.14</httpclient.version>
      <httpclient5.version>5.1.4</httpclient5.version>
      <httpcore.version>4.4.16</httpcore.version>
      <httpcore5.version>5.1.5</httpcore5.version>    
      <javax-activation.version>1.2.0</javax-activation.version>
      <javax-annotation.version>1.3.2</javax-annotation.version>
      <javax-cache.version>1.1.1</javax-cache.version>    
      <javax-json.version>1.1.4</javax-json.version>
      <javax-jsonb.version>1.0</javax-jsonb.version>
      <javax-mail.version>1.6.2</javax-mail.version>
      <javax-money.version>1.1</javax-money.version>    
      <javax-websocket.version>1.1</javax-websocket.version>
      <jaxen.version>1.2.0</jaxen.version>    
      <json-path.version>2.7.0</json-path.version>
      <json-smart.version>2.4.8</json-smart.version>
      <jsonassert.version>1.5.1</jsonassert.version>
      <jstl.version>1.2</jstl.version>
      <jtds.version>1.3.1</jtds.version>
      <junit.version>4.13.2</junit.version>
      <junit-jupiter.version>5.8.2</junit-jupiter.version>
      <kafka.version>3.1.2</kafka.version>    
      <log4j2.version>2.17.2</log4j2.version>
      <logback.version>1.2.11</logback.version>
      <lombok.version>1.18.24</lombok.version>
      <maven-clean-plugin.version>3.2.0</maven-clean-plugin.version>
      <maven-compiler-plugin.version>3.10.1</maven-compiler-plugin.version>
      <maven-dependency-plugin.version>3.3.0</maven-dependency-plugin.version>
      <maven-deploy-plugin.version>2.8.2</maven-deploy-plugin.version>
      <maven-help-plugin.version>3.2.0</maven-help-plugin.version>
      <maven-install-plugin.version>2.5.2</maven-install-plugin.version>
      <maven-invoker-plugin.version>3.2.2</maven-invoker-plugin.version>
      <maven-jar-plugin.version>3.2.2</maven-jar-plugin.version>
      <maven-javadoc-plugin.version>3.4.1</maven-javadoc-plugin.version>
      <maven-resources-plugin.version>3.2.0</maven-resources-plugin.version>
      <maven-war-plugin.version>3.3.2</maven-war-plugin.version>    
      <mongodb.version>4.6.1</mongodb.version>    
      <mysql.version>8.0.31</mysql.version>    
      <rabbit-amqp-client.version>5.14.2</rabbit-amqp-client.version>
      <rabbit-stream-client.version>0.5.0</rabbit-stream-client.version>
      <spring-framework.version>5.3.24</spring-framework.version>
      <spring-kafka.version>2.8.11</spring-kafka.version>
      <spring-security.version>5.7.6</spring-security.version>
      <spring-session-bom.version>2021.2.0</spring-session-bom.version>
      <sqlite-jdbc.version>3.36.0.3</sqlite-jdbc.version>
      <thymeleaf.version>3.0.15.RELEASE</thymeleaf.version>
      <thymeleaf-extras-data-attribute.version>2.0.1</thymeleaf-extras-data-attribute.version>
      <thymeleaf-extras-java8time.version>3.0.4.RELEASE</thymeleaf-extras-java8time.version>
      <thymeleaf-extras-springsecurity.version>3.0.5.RELEASE</thymeleaf-extras-springsecurity.version>
      <thymeleaf-layout-dialect.version>3.0.0</thymeleaf-layout-dialect.version>
      <tomcat.version>9.0.70</tomcat.version>    
      <versions-maven-plugin.version>2.10.0</versions-maven-plugin.version>
      <webjars-locator-core.version>0.50</webjars-locator-core.version>    
      <xml-maven-plugin.version>1.0.2</xml-maven-plugin.version>
      <xmlunit2.version>2.9.0</xmlunit2.version>
  </properties>

因此,以后我们导入依赖包时默认是不需要配置版本的;但是如果导入的包没有在依赖中管理,那么就需要我们手动配置版本了。

注:Spring Boot官方文档列出Spring Boot项目中我们可以使用的所有依赖及其默认版本。

1.2、启动器

所谓“启动器”,即:Spring Boot应用依赖的一个个spring-boot-starter-XXX项目。

SpringBoot将所有的功能场景都抽取出来,做成一个个的starter (启动器),我们只需要在项目中引入这些starter即可将所有相关的依赖都导入进来 , 我们要用什么功能就导入什么样的场景启动器即可 ;我们未来也可以自己自定义starter

如:spring-boot-starter-web启动器:帮我们导入了web模块正常运行所依赖的组件。

pom.xml文件:

<!-- web场景启动器 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

注: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注解说明:这是一个配置类。配置类就对应Springxml配置文件。

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<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    List<String> 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方法的作用是:获取候选的配置。
  • 该方法通过调用ImportCandidatesload方法导入候选的配置!

(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<URL> urls = findUrlsInClasspath(classLoaderToUse, location);
    List<String> 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-autoconfigurejar包中。

(6)SpringBoot会向容器中导入非常多的自动配置类(xxxAutoConfiguration),就是向容器中导入这个场景需要的所有组件,并配置好这些组件。

(7)有了自动配置类,免去了我们手动编写配置注入功能组件等工作。

2.3、SpringApplication类

2.3.1、SpringApplication类的作用

SpringApplication类主要完成以下四件事情:

  • 推断应用的类型是普通的项目还是Web项目。
  • 查找并加载所有可用初始化器,并设置到initializers(初始化)属性中。
  • 找出所有的应用程序监听器,设置到listeners属性中。
  • 推断并设main方法的定义类,找到运行的主类。

好了,今天就分享到这里,如果有点点帮助,记得点赞、收藏、分享,谢啦!

相关推荐

Maven打包三种方法和常用命令大全

maven常用打包命令1方法一:使用maven-jar-plugin和maven-dependency-plugin插件打包2方法二:使用maven-assembly-plugin插件打包在pom...

Maven plugin是怎么回事

每天都在用maven,也用到mavenplugin,但是它的运行机制是怎么样的,你知道吗?Maven插件(Mavenplugins)是一种扩展工具,用于扩展和增强Maven构建过程的功能。插件可以...

Java面试题:讲一下maven的生命周期

Maven生命周期的核心机制Maven的生命周期定义了项目构建和部署的标准化流程,分为3个主要生命周期...

Spring Boot 运行原理(5分钟速解)

SpringBoot...

SpringBoot打包部署解析:jar包的生成和结构

SpringBoot打包部署解析SpringBoot项目支持两种常见的打包形式:jar包和war包。默认情况下创建的SpringBoot项目是采用jar包形式,如果项目需要war包...

Spring如何在运行期动态注册新的数据源?

最近在翻底稿的时候找到了一个之前跟小册交流群的群友讨论的话题,感觉这个主题还不错,所以本篇文章,我们就来研究一下本文标题所述的这个话题:SpringFramework如何在运行期动态注册新的数据源?...

盘点16个.Net开源项目

我是编程乐趣,一个10年.Net开发经验老程序员,点击右上方“关注”,每天为你分享开源项目和编程知识。今天一起盘点下,16个.Net开源项目,有博客、商城、WPF和WinForm控件、企业框架等。...

跨平台.NET应用UI组件DevExpress XAF v22.2亮点 - 支持.NET 7

DevExpressXAF是一款强大的现代应用程序框架,允许同时开发ASP.NET和WinForms。DevExpressXAF采用模块化设计,开发人员可以选择内建模块,也可以自行创建,从而以更快...

什么是双亲委派机制?(转载)

原文章地址:https://www.cnblogs.com/hollischuang/p/14260801.html什么是双亲委派机制...

DevExtreme控件升级(二)

HTML5/JS控件增强1.1无障碍DevExtremeHTML5/JS控件现在包含WAI-ARIA标记并支持屏幕阅读器。1.2字体图标我们已经改进了图标库并支持将图标作为一种字体,这使您能够...

腾讯 Go 性能优化实战

作者:trumanyan,腾讯CSIG后台开发工程师项目背景网关服务作为统一接入服务,是大部分服务的统一入口。为了避免成功瓶颈,需要对其进行尽可能地优化。因此,特别总结一下golang后台服务...

基于PHP的Laravel框架,盘点Github高星Web管理后台,效率为王!

在Web开发工作中,选择一个高效、稳定的后台管理系统是提高开发效率的关键。虽然PHP在近些年中的热度有所减退,但其上手简单、开源、灵活且被广泛应用的特点,仍然使其在编程语言排行榜中保持前十的位置。这表...

7.2k star!一款无比优雅的文档管理系统,免费开源!

说到文档管理,很多团队的文档管理都是一团糟,每个员工在自己本地写了各种Word文档、Excel表格、甚至还有手写的便签,到处都是,找起来就像大海捞针。有些聪明的团队开始用飞书来管理团队文档,但是...

10个顶级的CSS UI开源框架

随着CSS3和HTML5的流行,我们的WEB页面不仅需要更人性化的设计理念,而且需要更酷的页面特效和用户体验。作为开发者,我们需要了解一些宝贵的CSSUI开源框架资源,它们可以帮助我们更快更好地实现...

Java的jvm你应该知道的

JVM中类的装载是由类加载器(ClassLoader)和它的子类来实现的,Java中的类加载器是一个重要的Java运行时系统组件,它负责在运行时查找和装入类文件中的类。由于Java的跨平台性,经过编...