Spring boot跨三个小版本升级遇到的坑

1,818 阅读5分钟

Spring Boot 版本升级

记一次升级Spring Boot 版本遇到的问题.

因Spring Boot 版本太老,升级到较新的版本.

2.0.8.RELEASE->2.4.7

思路:

直接升级spring boot版本号,然后解决依赖报错问题,找不到类,方法等问题.走一步看一步.

好用的工具

可以在依赖中暂时加入以下依赖,其会在启动时检测新版本与老的配置冲突的问题并在控制台打印出来.优点是可以检测出所有的不适配配置项.

实测,在最新版 idea中IntelliJ IDEA 2021.1.2 (Ultimate Edition)中,pom中更新了spring boot 版本后,会提示application.yml文件中过时的配置.

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-properties-migrator</artifactId>
  <scope>runtime</scope>
</dependency>

spring cloud兼容问题

如果项目中使用了spring cloud,还要考虑spring boot和它的兼容性.

spring cloud对spring boot的兼容性查看

slf4j失效,提示找不到log.

可能的原因有三个:

  • 没有引用正确的lombok的jar包.一般来说在使用spring boot的情况下不会发生这种情况.可以查看classspath中是否包含相关的包.
  • 如果ide是idea,那么可能是idea的lombok插件版本过低. 同时这种错误应该是ide提示有问题,但是可以正常编译运行的,属于idea提示的问题,代码本身是没问题的.
  • 项目升级,同时项目层级关系比较复杂,依赖的管理没有做到一致,那么在某些项目中的spring boot版本已经和其他子项目的版本号不同,会导致其他项目找不到正确的lombok jar包.

一些方法及类的改变带来的运行报错

  1. MongoDbFactory -> MongoDatabaseFactory.

  2. Spring data 中的Sort 类方法改变,原来public的构造方法,现在变为private,并提供了其他静态方法来代替.

public Sort(Sort.Direction direction, List<String> properties) {
   ................
}

更改为

private Sort(Sort.Direction direction, List<String> properties) {
   ................
}

并新增了

public static Sort by(Sort.Direction direction, String... properties) {
   .............
}

改为使用静态方法by之后,正常运行.

  1. 包名的改变
import feign.hystrix.FallbackFactory;

改为

import org.springframework.cloud.openfeign.FallbackFactory;

MongoDb

  • MongoDbFactory 废弃 ,使用 MongoDatabaseFactory 代替.

  • 原来使用双注解@Id和@Field的方式在新版本spring data mongodb中会出现用ObjectId查询结果为空的错误.

改用新注解 @MongoId(targetType = FieldType.OBJECT_ID) 代替.

  • ObjectId构造方法更改,在com.shanda.common.util.ObjectIdUtils line 27.

spring data

Sort 类去除了实例化Sort的方法,使用静态方法 by 代替.

mongodb driver

表因

org.springframework.data.mongodb.UncategorizedMongoDbException
Command failed with error 301: 'Retryable writes are not supported' on server *.com: 27017. The full response is 
{"ok": 0.0, "code": 301, "errmsg": "Retryable writes are not supported", "operationTime": {"$timestamp": {"t": 1637724972, "i": 1
}
}
}
nested exception is com.mongodb.MongoCommandException: Command failed with error 301: 'Retryable writes are not 
supported' on server *.com: 27017. The full response is {"ok": 0.0, "code": 301, "errmsg": "Retryable writes are not supported", "operationTime": {"$timestamp": {"t": 1637724972, "i": 1
}
}
}

在3.6版本的java mongo driver中,新增了retryWrites.

升级过程刚好是跨过一个没有retryWrites到有的过程,所以出现错误.

在mongo 连接的uri中指定retryWrites=false关闭即可.详细可见

docs.mongodb.com/manual/core…

实体类

错误表因:

Cannot construct instance of com.*.*.domain.entity.app.AbstractCompositeContentApplicationEntity (no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information

jackson json转换更为严格,使用fastjson强制转换即可

错误表因:

Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of com.*.*.domain.proto.in.ForwardCmdProto (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

lombok的改动导致的,使用lombok的配置文件改正这个错误.

https://github.com/projectlombok/lombok/issues/1563

错误表因

org.springframework.data.mapping.MappingException: No property operator found on entity class com.shanda.npc.lab.domain.entity.usage.UsageRecord to bind constructor parameter to!

在于没有生成一个spring初始化bean会用到的空构造函数.

升级了sring boot版本之后,连带着lombok的版本也升级了,新版本中默认不再为@Date和@Value注解的类生成private的空构造方法

解决办法一:

降级到支持生成空构造函数的版本.

projectlombok.org/changelog

但是从changelog来看,1.16.22默认是打开,但从此之后的版本就默认关闭了.可能官方并不推荐这样操作吧.

此方法还有个缺点就是随着jdk的升级,这个版本的lombok后面也没法再使用,只能采用方法二解决.

鉴于我自己使用方法二并未成功,所以采用了此办法.

方法二:

使用lombok的config文件来开启某些特性.

java -jar lombok.jar config -g --verbose

在.m2文件夹下找到使用版本的lombok的jar,使用这个命令可以输出所有支持的config

在项目的根目录下新建lombok.config,将配置写入,即可.

lombok.noArgsConstructor.extraPrivate = true

随后可在target文件夹中查看编译好的class文件启用选项是否生效.

解决办法三:

使用lombok添加@NoArgsConstructor注解为实体类添加无参构造去除spring data 无法实例化的错误.

缺点是需要每个添加,巨多.而且要求后面新加的类也必须这样加

旧的配置文件更新

从以下配置

spring:
  application:
    name: file
  servlet:
    multipart:
      max-file-size: 100Mb
      max-request-size: 100Mb

更新到

spring:
  application:
    name: file
  servlet:
    multipart:
#      1048576L = 1mb
      max-file-size: 104857600
      max-request-size: 104857600

序列化问题

在pom中指定某些组件的版本号,如果当前pom的parent是spring,那么可以使用properties指定spring中管理的依赖版本号.

例如:


<properties>
    <jackson-bom.version>2.12.1</jackson-bom.version>
</properties>

其中jackson在较新版本spring中使用jackson-bom指定,具体如何使用,可以查看spring的dependency中具体如何使用的

jackson将Object类型转换为·抽象类的实例·出错,使用fastjson强转.

com.*.*.core.component.ChatMessageResolver
AbstractCompositeContentApplicationEntity appAbstractInfo=new JacksonUtils().convertValue(msg.getExtend(),new TypeReference<>(){});