SpringBoot&SpringCloud升级可能会出现的问题

本文记录了将SpringBoot和SpringCloud从旧版本升级到新版本过程中遇到的不兼容问题,如Kotlin版本升级导致的错误、OpenTracing相关依赖调整、Junit5引入、ShardingSphere的兼容性问题等,并提供了相应的解决策略。

1.背景

之前负责过我们中台的SpringBoot和Cloud的升级,特次记录分享一下项目中可能出现的问题,方便后续的人快速定位问题。以及下述选择的解决方案都是基于让升级的服务影响和改动最小以及提供通用的解决方案的提前进行选择的。

1.1版本说明

升级前(大部分):
springboot版本:2.2.5.RELEASE
spring-cloud版本:Hoxton.SR3

升级后(2023年02月):
springboot版本:2.7.5;
spring-cloud版本:2021.0.4;

选择版本逻辑:
见官方映射逻辑
https://spring.io/projects/spring-cloud

这里是引用

同时选择最新中使用最多最稳定的版本。

2.升级带来可能不兼容问题

2.1ClassDefFoundError: kotlin/reflect/TypesJVMKt

升级kotlin版本<kotlin.version>1.6.21</kotlin.version>

2.2 NoClassDefFoundError: org/springframework/cloud/openfeign/ribbon/LoadBalancerFeignClient

问题原因:
io.opentracing.contrib.spring.cloud.feign.TraceFeignContext#addTracingClient 找不到对应的类
spring-cloud-netflix-ribbon 已从 SpringCloud 中删除
在这里插入图片描述
opentracing-spring-cloud-starter 作者没有时间更新对应新版的 Spring-cloud
见:
https://github.com/opentracing-contrib/java-spring-cloud/issues/312
https://github.com/opentracing-contrib/java-spring-cloud/pull/324

解决方案:
1.按需考虑是否替换为最新的OpenTelemetry,需结合自己公司的监控体系,影响较大

2.重写io.opentracing.contrib.spring.cloud.feign.TraceFeignContext#getInstances,影响小,关键代码如下:

package io.opentracing.contrib.spring.cloud.feign;
// 注意上面的package要同opentacing路径一致才能替换

public class CompatibleTraceFeignContext extends TraceFeignContext {

    private final FeignContext delegate;
    private final Tracer tracer;
    private final List<FeignSpanDecorator> spanDecorators;

    public CompatibleTraceFeignContext(Tracer tracer,
                                       FeignContext delegate,
                                       BeanFactory beanFactory,
                                       List<FeignSpanDecorator> spanDecorators) {
        super(tracer, delegate, beanFactory, spanDecorators);
        this.delegate = delegate;
        this.tracer = tracer;
        this.spanDecorators = spanDecorators;
    }

    @Override
    public <T> T getInstance(String name, Class<T> type) {
        T object = this.delegate.getInstance(name, type);
        return (T) this.compatibleAddTracingClient(object);
    }

    @Override
    public <T> Map<String, T> getInstances(String name, Class<T> type) {
        Map<String, T> tracedInstances = new HashMap<>();
        Map<String, T> instances = this.delegate.getInstances(name, type);
        if (instances == null) {
            return tracedInstances;
        }

        for (Map.Entry<String, T> instanceEntry : instances.entrySet()) {
            tracedInstances.put(instanceEntry.getKey(), (T) this.compatibleAddTracingClient(instanceEntry.getValue()));
        }
        return tracedInstances;
    }

    private Object compatibleAddTracingClient(Object bean) {
        if (bean instanceof TracingClient) {
            return bean;
        }

        if (bean instanceof Client) {
            return compatibleBuildTracingClient((Client) bean, tracer);
        }

        return bean;
    }

    private TracingClient compatibleBuildTracingClient(Client delegate, Tracer tracer) {
        return new TracingClientBuilder(delegate, tracer)
                .withFeignSpanDecorators(spanDecorators)
                .build();
    }

}

2.3 升级SpringBoot 版本后,默认为Junit5,junit4相关类没有了

引入junit4或者修改换成Junit5写法(建议)

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>

junit4和junit5共存时,可能单测会执行不到junit4的方法,可以参考此链接 https://codeantenna.com/a/cMyp4oXyCU

2.4 org.springframework.dao.InvalidDataAccessApiUsageException: ConnectionCallback; isValid; nested exception is java.sql.SQLFeatureNotSupportedException: isValid

问题原因:
此问题是由于shrding版本过旧与springBoot-actuator不匹配,数据库健康检测失败。
具体原因见:https://github.com/apache/shardingsphere/issues/5882

原因的根源: shardingsphere-jdbc/shardingsphere-jdbc-core/src/main/java/org/apache/shardingsphere/driver/jdbc/unsupported/AbstractUnsupportedOperationConnection.java

@Override
    public final boolean isValid(final int timeout) throws SQLException {
        throw new SQLFeatureNotSupportedException("isValid");
    }

此问题会导致健康检测地址返回{“status”:“DOWN”},从而注册不上consul
解决方案:

  1. 按需考虑是否要升级shardin版本,不过是alpha版本,见:https://github.com/apache/shardingsphere/pull/6002。
  2. 重写

2.5 高版本spring循环依赖校验变严

当前设置:不建议使用循环依赖,如果有这种情况, 先定位问题尝试修复

2.6@FeignClient 兼容问题 不支持@RequestMapping 写在Client接口上

原因:
Caused by: java.lang.IllegalArgumentException: @RequestMapping annotation not allowed on @FeignClient interfaces at org.springframework.cloud.openfeign.support.SpringMvcContract.processAnnotationOnClass(SpringMvcContract.java:182)
解决方案:
重写SpringMvcContract

2.7reactor-core版本问题

Caused by: java.lang.ClassNotFoundException: reactor.util.context.ContextView
	at java.net.URLClassLoader.findClass(URLClassLoader.java:387)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:419)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:352)
	... 58 common frames omitted

升级升级reactor-core到3.4.3

2.8 spring-boot-starter-data-redis 版本不兼容

org.springframework.boot.actuate.metrics.cache.RedisCacheMetrics.missCount(RedisCacheMetrics.java:56)
更新spring-boot-starter-data-redis 版本与SpringBoot一致

2.9升级版本之后的Spring Cloud Stream(SCS)消费kafka无法正常反序列化payload.

SCS消费业务系统发送的的消息时Message的payload的数据类型依然是byte[], 没有按照旧版本的行为序列化为String
触发条件:

  1. 使用SCS(@StreamListener)消费kafka消息,且没有为payload指定具体类型(入参Message没有指定泛型,指定泛型为Object也不会反序列化)
    问题原因:
    SCS是使用了AbstractMessageConverter来对payload进行反序列化的, AbstractMessageConverter有几个实现,序列化的过程是一个过滤器的模式,默认情况下,ApplicationJsonMessageMarshallingConverter是第一个处理器,当没有指定泛型时且payload是byte[]类型时,旧版本的处理逻辑如下:
    在这里插入图片描述
    新版逻辑:
    在这里插入图片描述
    无法命中条件,所以原样输出btye数组。
    解决方案:指明泛型
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值