Spring Boot 升级3.x 指南

Spring Boot 升级3.x 指南

1. 升级思路

先创建一个parent项目,打包类型为pom,继承自spring boot的parent项目

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.x</version>
</parent>

然后把版本集中放在这个pom里面,示例如下

xml 复制代码
<properties>
    <!-- 建议添加全局变量 java.version,maven.compiler.source, maven.compiler.target-->
    <java.version>17</java.version>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <spring-cloud-dependencies.version>2022.0.4</spring-cloud-dependencies.version>
    <spring-cloud-starter-netflix.version>2.2.10.RELEASE</spring-cloud-starter-netflix.version>
</properties>

然后添加dependencyManagement节点,示例如下:

xml 复制代码
<dependencyManagement>  
    <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud-dependencies.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
                <version>${spring-cloud-starter-netflix.version}</version>
                <exclusions>
                    <exclusion>
                        <artifactId>jsr311-api</artifactId>
                        <groupId>javax.ws.rs</groupId>
                    </exclusion>
                    <exclusion>
                        <artifactId>jackson-annotations</artifactId>
                        <groupId>com.fasterxml.jackson.core</groupId>
                    </exclusion>
                    <exclusion>
                        <artifactId>jackson-core</artifactId>
                        <groupId>com.fasterxml.jackson.core</groupId>
                    </exclusion>
                    <exclusion>
                        <artifactId>jackson-databind</artifactId>
                        <groupId>com.fasterxml.jackson.core</groupId>
                    </exclusion>
                    <exclusion>
                        <artifactId>guava</artifactId>
                        <groupId>com.google.guava</groupId>
                    </exclusion>
                </exclusions>
            </dependency>
    <dependencies>
</dependencyManagement>

其它服务都继承这个pom文件,这样各个组件的版本就能统一起来了,将来如果某个组件要升级,直接升级这个项目的版本,其它的重新打包发布即可。

注意:

  1. 动手前一定要调研项目中使用的组件,某些组件是没法升级的。比如ElasticSearch,驱动版本和ElasticSearch server版本要一致,升级了就会报错。其它常见组件的有Nacos,Kafka,Mysql,RocketMQ,需要调研是否兼容低版本。
  2. 如果之前使用了Zuul 1.x作为Gateway,Zuul 2.x不开源并且难以升级,建议升级到Spring Cloud Gateway
  3. 如果使用了Zuul1.x的作为Proxy嵌入服务中,有两个思路,一个是使用Filter+HttpClient手动写转发代码,第二个思路是调研调用接口,使用Feign做转发
  4. Spring Boot 3.x 需要JDK17,建议使用OpenJDK17,Oracle的JDK17可能存在授权问题

2. 遇到的问题

  1. Zuul1.x 升级Spring Cloud Gateway,可以参考 (Zuul迁移至Spring Cloud Gateway踩坑记录)[https://blog.csdn.net/codeblf2/article/details/128093298\] ,此记录中服务使用的是k8s部署,转发直接配置uri,如果使用的是Nacos,网络上博客比较多,这里不再赘述。

  2. 如果是Spring Boot 1.x升级上来的,可能要注意循环依赖,添加以下可以解决:

    yaml 复制代码
    spring:
      main:
        allow-circular-references: true
  3. Spring Boot 3.x 支持优雅退出,添加以下配置开启

    yaml 复制代码
    # 打开优雅退出
    server:
      shutdown: graceful
    # 多长时间后强制杀掉进程
    spring:
      lifecycle:
        timeout-per-shutdown-phase: 30s
  4. Beancopier可能没法用了,可以使用BeanUtil.copyProperties替换

  5. JDK8升级到JDK17,javax包变成了jakarta,需要替换所有的javax.annotation和javax.validation等,但javax.mail没有变,当jakarta.xxx不存在时,还是使用javax.xxx即可

  6. 如果引入外部配置文件,使用spring.cloud.bootstrap.additional-location=/data/config/bootstrap.yml,/data/config/bootstrap2.yml即可

  7. 如果依赖的一些jar中依赖一些类但由于升级,依赖类已经不存在了,典型的就是WebMvcConfigurerAdapter.class,之前是继承WebMvcConfigurerAdapter,Spring Boot 3.x 已经改成了实现接口WebMvcConfigurer,可能会出现FileNotFoundException,此时可能难以定位是哪个jar,参考SpringBoot版本升级引起的FileNotFoundException------WebMvcConfigurerAdapter.class

  8. Spring Cloud Gateway 配置文件参考(可能遇到的问题已经写在了注释中):

    yaml 复制代码
    spring:
      cloud:
        gateway:
          # 默认过滤器
          default-filters:
           # 将path中第一个/xxx去掉 比如请求是 https://www.xxx.com/a/b/c?d=1
           # 经过这个过滤器之后就是 https://www.xxx.com/b/c?d=1
           - StripPrefix=1
           # 下面这两个过滤器是gateway和后面的服务都配置了跨域头,防止返同样的回头有多个导致跨域失败
           # 典型的 access-control-allow-credentials: true,true 返回到前端导致跨域失败
           - DedupeResponseHeader=access-control-allow-credentials,RETAIN_UNIQUE
           - DedupeResponseHeader=access-control-allow-origin,RETAIN_UNIQUE
          routes:
          	# 服务名
            - id: user
              # 转发到的url 下面的示例是k8s内部转发
              # 如果使用服务名转发 开头应该是lb:xxx
              # 这个端口后不要加任何东西 因为转发的时候会忽略掉
              # 比如 http://service-user.inner:8080/aaa最后拼接出来是http://service-user.inner:8080,/aaa就忽略了
              uri: http://service-user.inner:8080
              predicates:
              	# 匹配的请求url中的path 下面这个会匹配到 http://www.xxx.com/gateway/user/login?userName=AAA
                - Path=/gateway/user/**
              filters:
                # StripPrefix:去除原始请求路径中的前1级路径
                # 会把 http://www.xxx.com/gateway/service1/login中的service1去掉
                - StripPrefix=1
                # 在转发后的url添加的前缀 经过这个filter 转发url就变成了 http://service-user.inner:8080/service-user
                - PrefixPath=/service-user
     # 这里讲一下全流程
     # 以请求为 http://www.xxx.com/gateway/user/login?userName=AAA为例 这个url是要登录,登录服务名为service-user
     # 断言规则 spring.cloud.routes > predicates > Path=/gateway/user/** 能匹配到url http://www.xxx.com/gateway/user/login?userName=AAA
     # 第一步是默认过滤器 经过 spring.cloud.gateway.default-filters > StripPrefix=1 这个配置后就变成了 http://www.xxx.com/user/login?userName=AAA
     # 第二步是routers过滤器 spring.cloud.routes下的id=user的 filters > StripPrefix=1会将 http://www.xxx.com/user/login?userName=AAA的/user去掉,变成了   http://www.xxx.com/login?userName=AAA 变成
     # 第三步是routers过滤器 spring.cloud.routes下的id=user的 filters > PrefixPath=/service-user 会将 http://www.xxx.com/login?userName=AAA 变成 http://service-user.inner:8080/service-user服务/login?userName=AAA
     # 经过上面的处理后,最终会转发到 service-user服务
     # response中的header如果有跨域header 会经过 spring.cloud.gateway.default-filters > DedupeResponseHeader过滤器将重复的header去掉
相关推荐
向前看-1 小时前
验证码机制
前端·后端
xlsw_1 小时前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis
神仙别闹2 小时前
基于java的改良版超级玛丽小游戏
java
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭3 小时前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
暮湫3 小时前
泛型(2)
java
超爱吃士力架3 小时前
邀请逻辑
java·linux·后端
南宫生3 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
转码的小石3 小时前
12/21java基础
java
李小白663 小时前
Spring MVC(上)
java·spring·mvc
GoodStudyAndDayDayUp4 小时前
IDEA能够从mapper跳转到xml的插件
xml·java·intellij-idea