背景
项目之前一直使用Spring Cloud Dalston.SR5,但是此版本2018年12月软件生命周期要结束,为了后续安全和维护的需要,需要将对版本进行升级。先从官网上分析D版本的后续版本的变更,发现大部分组件基本是兼容的,这里只列出对升级有重大影响的部分变化:
- Edgware:依赖的spring boot版本升级仍然是1.5, 许多组件的名称变化
- Finchley:依赖的spring boot版本升级到2.0,真正的大版本升级,重大变化
- Greenwich:依赖的spring boot版本升级到2.1,支持java11
然后我们再搜索网上其它人升级的经验和难度,最后决定将目前的spring cloud直接升级最新版本:Greenwich.SR1
升级的详细步骤和碰到的坑
spring-cloud-dependencies版本从Dalston.SR5到Greenwich.SR1
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.SR5</version>
-->
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.SR1</version>
spring boot 版本从1.5.13 升级到2.1.4
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.13.RELEASE</version>
-->
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
spring cloud的组件的artifactId名称变更: 左边是旧,右边是新的
spring-cloud-starter-eureka --> spring-cloud-starter-netflix-eureka-client
spring-cloud-starter-eureka-server --> spring-cloud-starter-netflix-eureka-server
spring-cloud-starter-feign --> spring-cloud-starter-openfeign
spring-cloud-starter-hystrix -> spring-cloud-starter-netflix-hystrix
将pom.xml中对应的artifactId名称修改为最新的名称
其它artifactId部分修改见这里:E版本 https://github.com/spring-projects/spring-cloud/wiki/Spring-Cloud-Edgware-Release-Notes
Feign的变化
feign除了上面提到组件的artifactId名称重名为 spring-cloud-starter-openfeign外,还有以下部分发生变化:
包名发生改变:
org.springframework.cloud.netflix.feign.**.java -> org.springframework.cloud.openfeign.**.java
@FeignClient增加一个属性值contextId
之前的版本如果有存在两个name属性相同@FeignClient对象,不会报错,但是升级后,会将相同name属性的实例对象认为是同一个Bean从而抛出如下异常: “The bean ‘icc-authority.FeignClientSpecification’, defined in null, could not be registered. A bean with that name has already been defined in null and overriding is disabled.”
解决方案是在@FeignClient注解里增加contextId值将为bean id,如下:
@FeignClient(name="authority", fallbackFactory = IAccountServiceFallbackFactory.class, contextId = "accountService")
public interface IAccountService {
}
Feign连接池
由于Spring Cloud D版本的Fegin使用httpclient做连接池,默认创建连接池对象的可配置项太少且连接池中可能存在处于半连接状态的连接(关于httpclient半连接状态bug见这篇文章 ),所以自己实现了HttpClient实例。到了G版本,如果实现Httpclient做连接池则,默认使用系统自己创建的httpclient对象,另外观察源码HttpClientFeignLoadBalancedConfiguration 创建 httpclient的代码,不仅增加定时器关闭异常的连接解决半连接的问题,连接池的参数都是可配置的。
解决方案:
方案一. 所以去除自己的httpclient实例,使用默认的httpclient实例
方案二. 由于默认实现httpclient依然有部分参数不*配置,我们仍然可以继续使用自己的httpclient,在创建httpclient的方法上标记@Primay,且方法名称不可以为httpclient,否则会报错
@Bean
@Primary
public HttpClient httpClientDefault(FeignHttpClientPoolConfiguration feignHttpClientPoolConfiguration){
HttpClient httpClient = ….;
return httpClient;
}
Spring Cloud Feign的文件上传实现的依赖jar包的升级
如果有使用feign实现文件上传,则会抛出如下异常:
Failed to parse multipart servlet request; nested exception is java.io.IOException: org.apache.tomcat.util.http.fileupload.FileUploadException: the request was rejected because no multipart boundary was found
解决方法:
io.github.openfeign.form.feign-form和io.github.openfeign.form.feign-form-spring从3.0.3 版本升级到 3.8.0
commons-fileupload升级到1.4
无法找到jedis相关的组件
新版本使用Spring Data Redis 2.0,此版本已经将将jedis移除,默认使用的 Lettuce组件
解决方案一:
不使用jedis,直接升级到使用Lettuce,如果代码中没有显示使用jedis,建议使用此方案
然后对redis配置参数根据ide的提示修改即可
解决方案二:
增加jedis依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
Druid连接池版本升级
抛出异常:Caused by: java.lang.ClassNotFoundException: org.apache.log4j
原因:新版本Spring Boot不要使用log4j,但是支持log4j2
解决方法:
1. 配置drui的属性filters值为log4j2:
2. 升级com.alibaba.druid.jar包升级到1.1.16
分布插件pagehelper 升级:
异常:pagehelper 无法正常工作
原因:当前的使用pagehelper-spring-boot-starter 不支持spring boot 2.1.x
解决方案:
1. com.github.pagehelper: pagehelper-spring-boot-starter 升级到 1.2.10, 用于支持spring boot 2.1.x
2. 对应的 com.github.pagehelper: pagehelper 升级到5.1.8
属性配置的变化:
应用的上下文路径:server.context-path: authority --> server.servlet.context-path: authority
上传文件参数配置:spring.http.multipart.* -> spring.servlet.multipart.*
如原 spring.http.multipart.maxFileSize:5Mb -> spring.servlet.multipart.maxFileSize:5MB
同时这里5Mb中的Mb的必须是大写字母,必须是5MB,否则会抛出异常:failed to convert java.lang.String to @org.springframework.boot.convert.DataSizeUnit org.springframework.util.unit.DataSize
@NotBlank, @NotEmpty 注解已经纳入了JSR303,不需要在使用hibernate提供的注解了
org.hibernate.validator.constraints.NotBlank --> javax.validation.constraints.NotBlank
org.hibernate.validator.constraints.NotEmpty --> javax.validation.constraints.NotEmpty
zipkin
在新的版本中,@EnableZipkinServer已经被标记@Deprecated,已经不推荐自行定制编译服务的方式运行zipkin。官方推荐下载jar直接运行
curl -sSL https://zipkin.io/quickstart.sh | bash -s
java -jar zipkin.jar
详细见这里: https://github.com/apache/incubator-zipkin#quick-start
https://github.com/apache/incubator-zipkin/blob/master/zipkin-server/src/main/java/zipkin/server/EnableZipkinServer.java
其它:
在升级后,经常抛出没有找到类的异常:java.lang.NoClassDefFoundError
对于这类错误,通过只要找到对应的jar将其升级到最新的版本就可以解决。
这也告诉我们如果要使用第三方的组件,一定要使用社区活跃的组件,否则一旦此组件出现安全问题或系统升级版本时,此组件不兼容其它的组件,则必须要使用新组件替换此组件的功能。
版本升级后会有deprecated的类或方法,所以要注意看console中build的warning信息
由于我们使用的Spring Cloud最近的版本,升级依赖jar通常只要升级到最新版本基本没问题
Spring Cloud Netflix 进入项目进入维护模式阶段
Spring Cloud Netflix 除了spring-cloud-netflix-eureka-* 和spring-cloud-netflix-concurrency-limits 模块以外,全部进入维护模式,详细如下:
○ spring-cloud-netflix-archaius
○ spring-cloud-netflix-hystrix-contract
○ spring-cloud-netflix-hystrix-dashboard
○ spring-cloud-netflix-hystrix-stream
○ spring-cloud-netflix-hystrix
○ spring-cloud-netflix-ribbon
○ spring-cloud-netflix-turbine-stream
○ spring-cloud-netflix-turbine
○ spring-cloud-netflix-zuul
以下表中左边的模块也已经进入维护模块,右边是他的将来替代者
- Hystrix已经进入维护模式,建议使用Resillence4j替换,对应的Hystrix Dashboard和Turbine也会被淘汰,建议使用Resillence4j自带Micrometer进行替换。 Resillence4j的孵化地址:https://github.com/spring-cloud-incubator/spring-cloud-circuitbreaker
- Ribbion被Spring Cloud Loadbalancer替换,孵化地址:https://github.com/spring-cloud-incubator/spring-cloud-loadbalancer
- Zuu1 1 被 Spring Cloud GateWay替换: 有Spring Cloud Gateway和Zuul 1.x的性能对比:http://www.itmuch.com/spring-cloud-sum/performance-zuul-and-gateway-linkerd/
- Archaius 1的替代Spring Boot external config + Spring Cloud Config
什么是维护模式:Spring Cloud 不会向对应的模块增加新的功能,但是他们仍然会修复出现的bug和安全问题,以及接受社区的pull request。
即使Greenwich版本被普遍采用后,Spring Cloud仍然保证会继续支持以上的模块至少一年