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),启动应用
相关推荐
圈圈编码18 分钟前
Spring Task 定时任务
java·前端·spring
俏布斯31 分钟前
算法日常记录
java·算法·leetcode
276695829235 分钟前
美团民宿 mtgsig 小程序 mtgsig1.2 分析
java·python·小程序·美团·mtgsig·mtgsig1.2·美团民宿
爱的叹息36 分钟前
Java 连接 Redis 的驱动(Jedis、Lettuce、Redisson、Spring Data Redis)分类及对比
java·redis·spring
程序猿chen1 小时前
《JVM考古现场(十五):熵火燎原——从量子递归到热寂晶壁的代码涅槃》
java·jvm·git·后端·java-ee·区块链·量子计算
松韬1 小时前
Spring + Redisson:从 0 到 1 搭建高可用分布式缓存系统
java·redis·分布式·spring·缓存
绝顶少年2 小时前
Spring Boot 注解:深度解析与应用场景
java·spring boot·后端
心灵宝贝2 小时前
Tomcat 部署 Jenkins.war 详细教程(含常见问题解决)
java·tomcat·jenkins
天上掉下来个程小白2 小时前
Redis-14.在Java中操作Redis-Spring Data Redis使用方式-操作列表类型的数据
java·redis·spring·springboot·苍穹外卖
ゞ 正在缓冲99%…2 小时前
leetcode22.括号生成
java·算法·leetcode·回溯