Spring Boot 升级3.x 指南

Spring Boot 升级3.x 指南

1. 升级思路

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


    org.springframework.boot
    spring-boot-starter-parent
    3.x

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

<properties>
    
    <java.version>17java.version>
    <maven.compiler.source>17maven.compiler.source>
    <maven.compiler.target>17maven.compiler.target>
    <spring-cloud-dependencies.version>2022.0.4spring-cloud-dependencies.version>
    <spring-cloud-starter-netflix.version>2.2.10.RELEASEspring-cloud-starter-netflix.version>
properties>

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

<dependencyManagement>  
    <dependencies>
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-dependenciesartifactId>
                <version>${spring-cloud-dependencies.version}version>
                <type>pomtype>
                <scope>importscope>
            dependency>
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-starter-netflix-ribbonartifactId>
                <version>${spring-cloud-starter-netflix.version}version>
                <exclusions>
                    <exclusion>
                        <artifactId>jsr311-apiartifactId>
                        <groupId>javax.ws.rsgroupId>
                    exclusion>
                    <exclusion>
                        <artifactId>jackson-annotationsartifactId>
                        <groupId>com.fasterxml.jackson.coregroupId>
                    exclusion>
                    <exclusion>
                        <artifactId>jackson-coreartifactId>
                        <groupId>com.fasterxml.jackson.coregroupId>
                    exclusion>
                    <exclusion>
                        <artifactId>jackson-databindartifactId>
                        <groupId>com.fasterxml.jackson.coregroupId>
                    exclusion>
                    <exclusion>
                        <artifactId>guavaartifactId>
                        <groupId>com.google.guavagroupId>
                    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升级上来的,可能要注意循环依赖,添加以下可以解决:

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

    # 打开优雅退出
    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 配置文件参考(可能遇到的问题已经写在了注释中):

    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去掉
    

你可能感兴趣的:(spring,boot,后端,java)