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

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

lipiwang 2025-03-20 16:15 5 浏览 0 评论

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注解说明:这是一个配置类。配置类就对应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 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方法的作用是:获取候选的配置。
  • 该方法通过调用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 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-autoconfigurejar包中。

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

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

2.3、SpringApplication类

2.3.1、SpringApplication类的作用

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

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

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

相关推荐

Qwen上新AI前端工程师!一句话搞定HTML/CSS/JS,秒变React大神

梦晨发自凹非寺量子位|公众号QbitAIQwen上新“AI前端工程师”WebDev,一句话开发网页应用。三大件HTML,CSS,JavaScript一个工具全包了,定睛一看用的还是Reac...

程序员的 JavaScript 代码该如何让计算机搞懂?

出自程序员之手的JavaScript代码,该如何变成计算机所能理解的机器语言呢?本文将带你走进JavaScript引擎内部,一探究竟。作者|LydiaHallie译者|弯月,责编|...

JavaScript:如何优雅的创建数组?

在JavaScript里,有多种方式可以创建数组,下面为你详细介绍:1.使用数组字面量这是最常用的创建数组的方法,使用方括号[]来创建数组。//创建一个空数组letemptyArray...

Jquery 详细用法

1、jQuery介绍(1)jQuery是什么?是一个js框架,其主要思想是利用jQuery提供的选择器查找要操作的节点,然后将找到的节点封装成一个jQuery对象。封装成jQuery对象的目的有...

HTML页面基本结构和加载过程

大家好,我是皮皮。前言对于前端来说,HTML都是最基础的内容。今天,我们来了解一下HTML和网页有什么关系,以及与DOM有什么不同。通过本讲内容,你将掌握浏览器是怎么处理HTML内容的,...

【HarmonyOS Next之旅】兼容JS的类Web开发(一)

目录1->概述1.1->整体架构2->文件组织2.1->目录结构2.2->文件访问规则2.3->媒体文件格式3->js标签配置3....

JavaScript初学者指南

如果你刚接触JavaScript,想必已经被“modulebundlersvs.moduleloaders”、“Webpackvs.Browserify”和“AMDvs.Common...

前端图片延迟加载详细讲解

原文链接:http://www.gbtags.com/gb/share/6366.htm?原本是打算昨天昨天下午的时候就写一篇关于前端图片延迟加载的详细技术的博客的,没想到下午公司项目出现了一些问题...

selenium:操作滚动条的方法(8)

selenium支持几种操作滚动条的方法,主要介绍如下:使用ActionChains类模拟鼠标滚轮操作使用函数ActionChains.send_keys发送按键Keys.PAGE_DOWN往下滑动...

jQuery 获取和设置HTML元素

jQuery中包含更改和操作HTML元素和属性的强大方法。我们可以通过这些方法来获取HTML元素中的文本内容、元素内容(例如HTML标签)、属性值等。text()方法text()方法可以用...

JavaScript脚本如何断言select下拉框的元素内容?

使用JavaScript脚本断言select下拉框的元素内容,需要考虑页面元素是否加载成功,出错时打印等,主要实现功能功能需包括如下几点:1.等待下拉框元素加载完成(支持超时设置)2.获取下...

JavaScript图片或者div拖动拖动函数的实现

/**拖动图片封装html格式:<imglay-src="${item.Resourcesurl}"alt="${item.ResourcesName}"...

JavaScript代码怎样引入到HTML中?

JavaScript程序不能独立运行,它需要被嵌入HTML中,然后浏览器才能执行JavaScript代码。通过<script>标签将JavaScript代码引入到HTM...

当你在Vue.js中想要隐藏 `` 标签时,可以这样做:

在Vue.js里,要是你想要搞掉`<br>`(换行)标签的效果,通常有几种路子:1.使用CSS嗯,最简单的办法就是用CSS搞定,控制元素的样式,让<br>标签彻底不显示...

php手把手教你做网站(三十)上传图片生成缩略图

三种方法:按比例缩小、图片裁切、预览图片裁切不管使用哪一个都是建立在图片已经上传的基础上;预览裁切上传,如果预览的图片就是原始大小,可以预览裁切以后上传(这里是个假象,下边会说明);1、上传以后按比例...

取消回复欢迎 发表评论: