升级Spring Cloud Alibaba 2021.1,Spring Cloud 2020.0.1,Spring Boot 2.4.2碰到的一系列兼容性问题及解决方案

2年前 (2022) 程序员胖胖胖虎阿
329 0 0

项目场景:

最近介于Log4j的漏洞,Spring boot也将版本升级到了2.6.2,并更新依赖版本Upgrade to Log4j2 2.17.0 , 本打算激进些直接把Spring Cloud升级到2021.0.x,Boot升级到2.6.2,奈何Cloud Alibaba还没兼容这块,发现直接强制升级存在循环依赖的问题,目前已知Nacos没问题,Sentinel和Dubbo存在循环依赖,所以还是乖乖升级到兼容版本,并且单独升级依赖的Log4j和Logback吧。

更新过程中碰到一系列的问题,及解决方案供大家少走些弯路。

Spring Cloud Alibaba版本信息详细可查看:版本说明


问题及解决方案:

1. bootstrap.yml不生效

例如报错:Param ‘serviceName’ is illegal, serviceName is blank

因为我的Nacos配置放到了bootstrap.yml,发现读取不到Nacos配置中心的配置,后续发现控制台也不显示Nacos相关信息。

原因

从Spring Boot 2.4版本开始,配置文件加载方式进行了重构。

package org.springframework.cloud.util;
public abstract class PropertyUtils {
    public static boolean bootstrapEnabled(Environment environment) {
        return (Boolean)environment.getProperty("spring.cloud.bootstrap.enabled", Boolean.class, false) || MARKER_CLASS_EXISTS;
    }

详细可查看官方说明:config-first-bootstrap

解决方案

<!-- 引入bootstrap -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>

2. 通过spring gateway访问其他服务503 service unavailable

原因

Spring Cloud 2020.0.0版本之前会自动引入Netflix Ribbon依赖,Netflix Ribbon功能跟loadbalancer一样,因Netflix公司停止维护Ribbon后, 在Spring Cloud 2020.0.0版本之后Spring使用loadbalancer替代了Ribbon, 但是loadbalancer依赖需要手动引入。

解决方案

# 引入loadbalancer
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>

后续问题

增加loadbalancer后启动提示:Spring Cloud LoadBalancer is currently working with the default cache. You can switch to using Caffeine cache, by adding it and org.springframework.cache.caffeine.CaffeineCacheManager to the classpath

解决方案是引入caffeine,或者关闭cache

<dependency>
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>caffeine</artifactId>
    <version>3.1.0</version>
</dependency>

访问其他服务时提示:LoadBalancerCacheManager not available, returning delegate without caching

先说有效方案,经过测试发现依赖有问题,引入依赖即可解决:

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context-support</artifactId>
  <version>5.2.21.RELEASE</version>
</dependency>

之前找到的网友配置,无效,以下可忽略,仅做记录

spring:
	cloud:
    loadbalancer:
      ribbon:
        enabled: false
      cache:
        enabled: true
        caffeine:
          spec: initialCapacity=500,expireAfterWrite=5s

但是发现配置有可能还会存在提示,没有生效!网络上有说Naocs discovery依赖有冲突导致没生效,exclusion spring-cloud-starter-netflix-ribbon,但是实际查看了下此版本并没有依赖这个包。

3. Loading class ‘com.mysql.jdbc.Driver’. This is deprecated. The new driver class is ‘com.mysql.cj.jdbc.Driver’. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.

原因

项目配置:

driverClassName: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
url: jdbc:log4jdbc:mysql://127.0.0.1:3306/tuine?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false

项目中使用到了log4jdbc-log4j2-jdbc4.1,升级后出现此错误提示。 因为mysql最新驱动名称为com.mysql.cj.jdbc.Driver,log4jdbc只支持com.mysql.jdbc.Driver,所以需要将自动加载数据库驱动关闭。

解决方案

resources文件下新增log4jdbc.log4j2.properties文件

log4jdbc.auto.load.popular.drivers=false
log4jdbc.drivers=com.mysql.cj.jdbc.Driver
log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator

4. Process finished with exit code 1

测试启动过程中,发现Idea直接退出,没有任何提示输出。这是Idea的设置问题

解决方案

在启动的Edit Configuration里设置指定服务的Active profiles,例如:local

5. Spring Cloud Gateway GlobalFilter自定义过滤中的同步调用和Feign调用,java.lang.IllegalStateException: block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-2

原因

在NonBlocking线程中再调用阻塞方法。例如Netty的线程就不允许阻塞,因为是在Netty的pipeline里,而Netty的线程本身是不允许阻塞的。

解决方案

修改为异步调用:eg.

 CompletableFuture<JSONObject> f  = CompletableFuture.supplyAsync(() -> {
     ResponseEntity<String> resEntity = restTemplate.exchange(authServiceUrl + "/permission", HttpMethod.GET, httpEntity, String.class);
     return JSONUtil.parseObj(resEntity.getBody());
 });
 JSONObject jsonObject = f.get();

6. Dubbo引入报错:org.springframework.beans.BeanInstantiationException: Failed to instantiate [feign.jaxrs2.JAXRS2Contract]: Constructor threw exception; nested exception is java.lang.NoClassDefFoundError: javax/ws/rs/Path

原因

网络上有说 javax/ws/rs/Path 是属于jsr311-api.jar 包下的,引入相关jsr311-api包即可,实际测试引入netflix-ribbon即可。

解决方案

引入ribbon

<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-ribbon -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
    <version>2.2.10.RELEASE</version>
</dependency>

7. When allowCredentials is true, allowedOrigins cannot contain the special value

提示allowedOrigins不允许设置*。2.4版本后需要修改此选项

When allowCredentials is true, allowedOrigins cannot contain the special value "*“since that cannot be set on the “Access-Control-Allow-Origin” response header. To allow credentials to a set of origins, list them explicitly or consider using"allowedOriginPatterns” instead.

解决方案

allowedOrigins更改为allowedOriginPatterns即可

allowedOrigins: "*"
# 替换为
allowedOriginPatterns: "*"

8. 升级后没有引入javax.validation包

原因

新版本中Spring Boot不自动包含此包,自行引入即可。

解决方案

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
    <version>2.3.3.RELEASE</version>
</dependency>

9. RestTemplate通过nacos服务名访问报错:java.net.UnknownHostException

此处还是因为2020版本不再使用netflix,没有了ribbon导致的问题,依旧是引入:

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

如出现以下报错:

An attempt was made to call a method that does not exist. The attempt was made from the following location:
    org.hibernate.validator.internal.xml.config.ValidationBootstrapParameters.<init>(ValidationBootstrapParameters.java:65)
The following method did not exist:
 javax.validation.BootstrapConfiguration.getClockProviderClassName()Ljava/lang/String;

解决方案为将 JavaEE7升级到JavaEE8

 <dependency>
    <groupId>javax</groupId>
    <artifactId>javaee-api</artifactId>
    <version>8.0.1</version>
</dependency>

相关文章

暂无评论

暂无评论...