likes
comments
collection
share

SpringBoot1.x升级到2.x 踩坑实践

作者站长头像
站长
· 阅读数 19

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第6天,点击查看活动详情

一、简述

1.文章由来

公司内部一直使用1.5.9.RELEASE版本的springboot,后来升级到2.x版本。项目升到2.x并在生产上使用约半年,期间遇到了一些坑,在此进行整理、分享。

2.升级原因

1.直接原因:log4j存在危险的安全漏洞,需要升级log4j版本。springboot1.5.9.RELEASE版本默认用的是2.7版本的log4j,替换为2.8.2之后的版本或者升级springboot版本可以解决问题。

2.版本过旧,有些已经闭源,或存在历史漏洞。1.5.9.RELEASE是2017年11月份发行,截止到现在,已经验证出许多漏洞,并通过版本升级修复了漏洞。

公司的devops平台的流水线构建时通过HUB扫描发现,历史版本有许多中高级的安全漏洞,必须升级修复。

3.新版本有很多有用的特性。

比如:2.x版本默认使用当前java中性能最好的HikariCP做数据库连接池。github.com/spring-proj…

3.同步升级spring-cloud

springboot升级,依赖的spring也会随之升级。此外,springcloud版本需要和springboot兼容,在springboot版本升级比较大的情况下,也可能需要升级。

参考:springboot-springcloud版本对应表:start.spring.io/actuator/in…

SpringBoot1.x升级到2.x 踩坑实践

推荐项目使用的版本:

springbootspringcloudspring
升级前1.5.9.RELEASEEdgware.SR14.3.13.RELEASE
升级后2.1.5.RELEASEGreenwich.SR35.1.7.RELEASE

二、解决版本变化遇到的问题

新旧版本有许多设计上的变化,如果不一一检查,并做相应改动,将导致许多程序问题! 每个项目使用的组件,配置各不相同,尽量使用下面方式逐一检查。

1.根据使用的技术栈,查看官方的指导,检验是否有变动

根据关键字搜索github中官方文档(github.com/spring-proj…

SpringBoot1.x升级到2.x 踩坑实践

目前使用的常用中间件需要关注的信息:

数据库: mysql、数据库连接池 搜索引擎: elasticsearch nosql: redis mq: rabbitmq、kafka

2.检查配置变化

2.1 配置变动的情况有

1.属性key变化。 2.属性value默认值有变化。 3.属性value单位发生变化。 例如:server.connection-timeout=10需要写成server.connection-timeout=10ms

2.2 根据已有的配置,查看官方的指导,检验是否有变动

根据关键字搜索github中官方文档(github.com/spring-proj…

SpringBoot1.x升级到2.x 踩坑实践

2.3 使用IDEA检验是否正确

将配置文件(yml、properties格式)拷贝到IDEA 示例: springboot的自动化配置中,不包含spring.application.names属性,所以会标注警告信息

SpringBoot1.x升级到2.x 踩坑实践

2.解决包依赖的版本冲突

包冲突的后果:

  1. 编译报错
  2. 项目无法正常启动,因为类结构可能有变化
  3. 项目可启动,运行中项目程序出错,因为有些类运行时才能执行

解决办法: 查看包依赖的版本,exclude包或者删除包依赖。注意:并非排除了冲突的包就能解决问题,因为可能解决了A代码缺少的类,但是导致了B代码缺失了类。

IDEA安装maven-helper插件,找到xxx-service模块的pom.xml文件

SpringBoot1.x升级到2.x 踩坑实践

三、常见的改变汇总

1.应用上下文路径

server.context-path改为server.servlet.context-path

2.eureka和feign的坐标变化

(1)feign

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-feign</artifactId>
</dependency>  

改为

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency> 

@FeignClient和@EnableFeignClients包名变了,需要重新import

(2)eureka-client

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency> 

改为

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

(3)eureka-server

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>

改为

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

(4)hystrix

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>

改为

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

3.feign调用超时设置

1.5.9.RELEASE

ribbon.ReadTimeOut=10000
ribbon.ConnectTimeout=10000

2.x.RELEASE

feign.client.default.readTimeout=10000 
feign.client.default.connectTimeout=10000

参考:Spring Cloud组件那么多超时设置,如何理解和运用? www.jianshu.com/p/c836a2836…

4.log4j2

我们使用的日志组件是log4j2

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

springboot-1.5.9.RELEASE版本的log4j2版本是2.7,而2.x以上版本至少是2.10.0版本

5.数据库连接池

springboot-1.5.9.RELEASE版本默认连接池用的是tomcat-jdbc,2.x版本用的是性能更好的HikariCP连接池

springboot-1.5.9.RELEASE版本,用spring.datasource.tomcat开头的参数配置连接池,示例

### 数据库连接配置
spring.datasource.tomcat.test-on-borrow = false
spring.datasource.tomcat.test-while-idle = true
spring.datasource.tomcat.time-between-eviction-runs-millis = 3600000
spring.datasource.tomcat.max-active=30

springboot-2.x.RELEASE版本,用spring.datasource.hikari开头的参数配置连接池,示例

### 数据库连接配置
# 最小空闲连接数,默认是10
spring.datasource.hikari.minimum-idle=5
## 连接池最大连接数,默认是10
spring.datasource.hikari.maximum-pool-size=15

可参考官方配置:github.com/brettwooldr…

注意: 1.HikariCP的作者推荐使用hikaricp的默认配置即可,因为作者对连接池的默认配置是经过大量优化得出的。如果有特殊的情况,可参考作者的建议:github.com/brettwooldr…

2.重要:不推荐只设置maximum-pool-size而不设置minimum-idle,因为maximum-pool-size一般是用来提供给突然的高并发而设置的。但如果当设置maximum-pool-size,而没有设置minimum-idle,系统会自动设置minimum-idle=maximum-pool-size,这样会导致应用从启动开始,一直保持maximum-pool-size大小的数据库连接,如果应用本不需要这么多连接,会浪费连接,而导致数据库连接数不够用。

6.上传附件的大小控制配置

spring.http.multipart.max-file-size=20mb 
spring.http.multipart.max-request-size=30mb

改为

spring.servlet.multipart.max-file-size=20mb 
spring.servlet.multipart.max-request-size=30mb

7.redis客户端

# boot1.x配置
spring:
  datasource:
  redis:
    database: 0 # Database index used by the connection factory.
    timeout: 0 # Connection timeout in milliseconds.
    pool:  # 默认使用jedis客户端
      max-active: 8 #
      max-idle: 8 # 
      max-wait: -1 # 
      min-idle: 1 # 
#boot2.x配置
spring:
  redis:
    database: 0 # Database index used by the connection factory.
    timeout: 0 # Connection timeout in milliseconds.
    lettuce: # 默认使用lettuce客户端,如果需要使用jedis客户端,需要修改pom.xml
      pool:
        max-active: 8 # 
        max-idle: 8 # 
        max-wait: -1 # 
        min-idle: 1 # 

如果需要改为jedis客户端,需要配置pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <!-- 1.5的版本默认采用的连接池技术是jedis  2.0以上版本默认连接池是lettuce, 在这里采用jedis,所以需要排除lettuce的jar -->
    <exclusions>
        <exclusion>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </exclusion>
        <exclusion>
            <groupId>io.lettuce</groupId>
            <artifactId>lettuce-core</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<!--spring2.0集成redis所需common-pool2-->
<!-- 必须加上,jedis依赖此  -->
<!-- spring boot 2.0 的操作手册有标注 大家可以去看看 地址是:https://docs.spring.io/spring-boot/docs/2.0.3.RELEASE/reference/htmlsingle/-->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.5.0</version>
</dependency>        

8.eureka注册中心

eureka的server与client采用http方式通信,所以eureka的server可以不用升级,但最好server一起升级,方便未来进行扩展。

未来会换用consul注册中心,因为eureka已经停止维护并且偶尔有异常报错的情况。

9.监控检查地址

如果依赖了spring-boot-actuator

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>    

原来的健康检查地址有变动,最常用的/info和/health已改为/actuator/info和/actuator/health.

影响: 应用监控的健康检查策略如果是:如果配置的是/info或者/health,需要修改为新的地址,不然应用启动后后,探针访问/info或/health地址后会报404,认为是启动失败。

四、建议

1.在项目迭代中预留足够的测试时间,升级的坑可能要测试较长一段时间后才能发现。

2.后端开发修改完配置后,要评估影响范围,并告知测试人员,一起对涉及的组件进行回归测试。

3.多查阅springboot、springcloud、hikaricp、redis等框架或组件的官方文档,留意不同版本的差异。