SpringBoot3 升级介绍

优质博文:IT-BLOG-CN

一、项目背景

截止2023.05.18,springboot发布了最新版本3.1.0。而在我们开发项目中,springboot一直使用的是1.5.8版本(相差6年的维护更新)。版本差距较大,很多新功能未能得到使用。例如近几年Loom的兴起,springboot也在3.0开始对虚拟线程进行了支持。

所以项目组开始计划对项目中的springboot版本进行升级改造。翻阅了springboot官方升级指引,不建议直接对springboot版本进行较大跨度的升级。小组制定了从1.5.8->2.1.0,2.1.0->2.7.9,2.7.9->3.0.5的升级改造计划。

二、Springboot简介

Springboot是Spring家族中的一个框架,它是用来简单应用程序的创建和开发过程,化繁为简,简化SSM(SpringMVC + Spring + MyBatis)框架的配置。比如说在使用SSM框架开发的时候,我们需要配置web.xml,配置spring,配置mybatis,并将它们整合到一起,而是用Springboot就不同了,它采用了大量的默认配置来简化这些文件的配置过程。

三、Springboot特性

【1】能够快速创建基于Spring的应程序。

【2】能够直接使用Java main方法启动内嵌的Tomcat服务器运行Spring Boot程序,不需要部署war包文件。

【3】提供约定的starter POM来简化Maven配置, 让Maven的配置变得简单。

【4】自动化配置,根据项目的Maven依赖配置,SpringBoot 自动配置Spring、SpringMVC等。

【5】提供了程序的健康检查等功能基本可以不使用XML配置文件,采用注解配置。

四、springboot模块介绍

我们先来对SpringBoot的源码模块来一个大致的了解,如下图:
1.5.x

2.1.x

2.7.x

3.0.x

从上图可以看到,主要有以下四个模块:

【1】spring-boot-project:整个SpringBoot框架全部功能在这个模块实现,SpringBoot项目95%的代码都在这里实现,源码总共有25万行左右。

【2】Spring-boot-samples:这个是SpringBoot给小伙伴们赠送的福利,里面包含了各种各样使用SpringBoot的简单demo,我们调试阅读源码的时候可以充分利用该模块。

【3】Spring-boot-sample-invoker:这个模块应该是跟sample模块有关,注意根pom.xml中有这么一句话:Samples are built via the invoker plugin(Samples模块通过invoker插件生成),该模块无代码。

【4】Spring-boot-tests:这个模块SpringBoot的测试模块,跟部署测试和集成测试有关。

因为SpringBoot的全部功能在spring-boot-project模块实现,因此下面重点来介绍下 spring-boot-project 模块。

五、spring-boot-project源码模块详解

先来看下spring-boot-project整体模块结构

1.5.x

2.1.x

2.7.x

3.0.x

模块众多我们真正要看的模块有spring-boot,spring-boot-autoconfigure,spring-boot-starters和spring-boot-actuator模块
【1】spring-boot-parent: 这个模块没有代码,是spring-boot模块的父项目,被其他子模块继承。

【2】spring-boot: 这个模块是SpringBoot项目的核心,可以说一些基础核心的功能都在这里实现,为SpringBoot的其他模块组件功能提供了支持,主要包括以下核心功能:

1、SpringApplication类,这个是SpringBoot的启动类,提供了一个静态的run方法来启动程序,该类主要用来创建并且刷新Spring容器 ( https://cloud.tencent.com/product/tkefrom=20065\&from_column=20065 )ApplicationContext.

2、支持选择不同的容器比如Tomcat,Jetty、等来作为应用的嵌入容器。

3、外部配置支持,这个指的是我们执行java -jar xxx.jar命令时可以带一些参数,比如执行java -jar demo.jar --server.port=8888来将应用端口修改为8888.

4、该模块内置了一些SpringBoot启动时的生命周期事件和一些容器初始化器(ApplicationContext initializers),来执行一些SpringBoot启动时的初始化逻辑。

【3】spring-boot-autoconfigure: 这个模块跟SpringBoot的自动配置有关。比如SpringBoot能基于类路径来自动配置某个项目模块,自动配置最为关键的注解是@EnableAutoConfiguration,这个注解能触发Spring上下文的自动配置。

除了根据类路径来进行自动配置外,还有根据容器中是否存在某个bean等方式来进行自动配置。

【4】spring-boot-starters: 这个模块是跟SpringBoot的启动依赖有关。SpringBoot通过提供众多起步依赖降低项目依赖的复杂度。起步依赖其实就是利用maven项目模型将其他相关的依赖给聚合起来,里面各种依赖的版本号都给定义好,避免用户在引入依赖时出现各种版本冲突,方便了我们的使用。

注意,该模块没有代码,主要是通过maven的pom.xml来组织各种依赖。

【5】 spring-boot-actuator: 这个跟SpringBoot的监控有关。可以通过HTTP端点或JMX等来管理和监控应用。审计、运行状况和度量收集可以自动应用到应用程序。这个监控模块是开箱即用的,提供了一系列端点包括HealthEndpoint, EnvironmentEndpoint和BeansEndpoint等端点。

用一张思维导图解释模块关系

六、springboot启动原理介绍

在springboot升级时,遇到问题,需要debug Springboot启动过程原码。不熟悉springboot启动过程,会增大问题排查难度。

内置tomcat

我们开发任何一个Spring Boot项目,都会用到如下的启动类@SpringBootApplication

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

@SpringBootApplication背后的秘密

@SpringBootConfiguration 相当于@Configuration,意义在于能让@SpringBootApplication的配置类能被@ComponentScan扫描。

@Configuration的注解类标识这个类可以使用Spring IoC容器作为bean定义的来源。

提到@Configuration就要提到他的搭档@Bean。使用这两个注解就可以创建一个简单的spring配置类,可以用来替代相应的xml配置文件。

@Bean注解告诉Spring,一个带有@Bean的注解方法将返回一个对象,该对象应该被注册为在Spring应用程序上下文中的bean。

@ComponentScan功能其实就是自动扫描并加载符合条件的组件(比如@Component和@Repository等)或者bean定义,最终将这些bean定义加载到IoC容器中。

我们可以通过basePackages等属性来细粒度的定制@ComponentScan自动扫描的范围,如果不指定,则默认Spring框架实现会从声明@ComponentScan所在类的package进行扫描。

注:所以SpringBoot的启动类最好是放在root package下,因此默认不指定basePackages。

@EnableAutoConfiguration 用于启用自动装配,路径扫描、组件装配等通过此注解实现。

@EnableAutoConfiguration的理念和做事方式其实一脉相承,简单概括一下就是,借助@Import的支持,收集和注册特定场景相关的bean定义。

@EnableAutoConfiguration会根据类路径中的jar依赖为项目进行自动配置,如:添加了spring-boot-starter-web依赖,会自动添加Tomcat和Spring MVC的依赖,Spring Boot会对Tomcat和Spring MVC进行自动配置。

@EnableAutoConfiguration作为一个复合Annotation,其自身定义关键信息如下:

1.5.x


2.7.x


3.0.x

其中,最关键的要属@Import(AutoConfigurationImportSelector.class),借助AutoConfigurationImportSelector,@EnableAutoConfiguration可以帮助SpringBoot应用将所有符合条件的@Configuration配置都加载到当前SpringBoot创建并使用的IoC容器。就像一只"八爪鱼"一样,借助于Spring框架原有的一个工具类:SpringFactoriesLoader的支持,@EnableAutoConfiguration可以智能的自动配置功效才得以大功告成!

SpringFactoriesLoader属于Spring框架私有的一种扩展方案,其主要功能就是从指定的配置文件META-INF/spring.factories加载配置,并实例化,加入IOC容器中。

深入探索SpringApplication执行流程

main方法作为入口,SpringApplicationRunListener是一个更底层的接口,它可以监听Spring应用程序中的更多事件,包括应用程序的启动和关闭、上下文创建和刷新、以及各种错误和异常。SpringApplicationRunListener的实现可以在应用程序的生命周期的任何时候被调用。

ApplicationListener是一个更高层次的接口,它只能监听Spring应用程序中的特定事件,如上下文刷新事件、上下文关闭事件等。ApplicationListener的实现只能在应用程序上下文创建之后才能被调用。


外置tomcat: spring boot war启动是利用Servlet 3.0新增的ServletContainerInitializer接口结合SPI(Service Provider Interface)机制实现的。

1.设置当前项目的打包方式,启动类所在目录的pom文件

<packaging>war</packaging>

2.让tomcat相关的依赖不参与打包部署 ,因为外置tomcat服务器已经有这些jar包

<!--让它不参与打包部署,或者排除内嵌tomcat-->
<dependency>
    <artifactId>spring-boot-starter-tomcat</artifactId>
    <groupId>org.springframework.boot</groupId>
    <scope>provided</scope>
</dependency>

3.支持启动springboot应用,需要在启动类

public class TomcatStartSpringBoot extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(Application.class);
    }
}

4.配置并启动tomcat

5.根据Servlet3.0规范,找到ServletContainerInitializer ,进行实例化。包路径:orgspringframeworkspring-web.3.14.RELEASEspring-web-4.3.14.RELEASE.jar!METAINFservicesjavax.servlet.ServletContainerInitializer。

6.创建实例,SpringServletContainerInitializer将@HandlesTypes(WebApplicationInitializer.class)标注的所有这个类型的类都传入到onStartup方法的Set集合,为这些WebApplicationInitializer类型的类创建实例并遍历调用其onStartup方法。

7.SpringServletContainerInitializer方法中又调用每一个initializer的onStartup方法。即先调用SpringServletContainerInitializer实例的onStartup方法,在onStartup()方法内部又遍历每一个WebApplicationInitializer类型的实例,调用其onStartup()方法。

8.我们的SpringBootServletInitializer的实例(com.web.application)会被创建对象,并执行onStartup方法。onStartup主要是createRootApplicationContext和addListener。

9.createRootApplicationContext主要干了

  • createSpringApplicationBuilder(),类似于内置tomcat初始化过程
  • 注册一个新的ParentContextApplicationContextInitializer、ServletContextApplicationContextInitializer
  • 添加listeners
  • builder.build(),返回
  • run(application),启动应用
相关推荐
yngsqq2 小时前
c# —— StringBuilder 类
java·开发语言
星星点点洲3 小时前
【操作幂等和数据一致性】保障业务在MySQL和COS对象存储的一致
java·mysql
xiaolingting3 小时前
JVM层面的JAVA类和实例(Klass-OOP)
java·jvm·oop·klass·instanceklass·class对象
风口上的猪20153 小时前
thingboard告警信息格式美化
java·服务器·前端
追光少年33224 小时前
迭代器模式
java·迭代器模式
超爱吃士力架5 小时前
MySQL 中的回表是什么?
java·后端·面试
扣丁梦想家5 小时前
设计模式教程:装饰器模式(Decorator Pattern)
java·前端·装饰器模式
drebander5 小时前
Maven 构建中的安全性与合规性检查
java·maven
drebander5 小时前
Maven 与 Kubernetes 部署:构建和部署到 Kubernetes 环境中
java·kubernetes·maven
王会举5 小时前
DeepSeek模型集成到java中使用(阿里云版)超简单版
java·阿里云·deepseek