SpringBoot 2.1.6.RELEASE 升级 2.7.6 爬坑分享
背景
Springboot 已于 22-11-24 发布了 Springboot 3.0.x 系列, 从 3.x 系列开始 最小的 Java 支持就升级为了 17, 基于此, 再回看自己目前维护的一些项目, 基本都还处于 2.1.6.RELEASE 这样的古早版本中上, 为了让自己的项目能够享受到新版本带来的技术红利 (eg: 更好的 JVM GC 设计, 成熟的 G1, 生产级别的 ZGC, 以及 Springboot 更快的启动速度), 于是决定对项目升级到 Springboot 3.0 的目标设定.
升级 Springboot 2.7.x 原因
由于升级到 Springboot 3.0, 官方推荐先将项目的主体结构升级到 Springboot 2.7.x 的最新版本, 因此本文将主要分享项目升级到Springboot 2.7.6(22年12月左右) 的一些爬坑解决方案.
升级思路
因为各自项目的依赖都不一样, 因此我们决定先基于升级底座版本, 解决 Maven 冲突&编译报错, 然后运行项目, 做接口测试, 测试环境运行一段时间, 发布生产, 去保障升级完整性.
升级项目依赖 Pom
关于 Springboot 与 Springcloud 的版本依赖关系, 建议大家参见官方文档说明, 因为我们这里选取的是 2.7.6 版本, 因此 Spring Cloud 可以去 2021.0.x 系列版本
确认好底座版本后, 我们针对项目的一些其他依赖也需要升级到最新版本, 除非有一些兼容性设计(大版本变更等, 例如 fastjson->fastjson2)
<!--spring 依赖 -->
<springboot.version>2.7.6</springboot.version>
<spring-cloud.version>2021.0.5</spring-cloud.version>
复杂问题汇总
Springboot 配置文件加载错误
从 Springboot 2.4.x 以后 配置文件加载逻辑出现了重大变更, 官方的目的是为了简化配置文件的设置, 同时也是为了兼容云原生中主流的 Volume 的配置支持
当你的项目配置文件出现了较为复杂的 application-xxx.yml 等组合时
为此官方提供了两个方案
- 兼容性方案, 回退新特性, 保留历史加载逻辑, 但这个兼容性方案会在 3.0 彻底下线, 因此只能是过渡折衷方案.
spring.config.use-legacy-processing = true
- 改造配置文件引入逻辑, 符合新加载逻辑写法, 但新写法理解上会较为复杂, 因此会考虑在 升级 3.0 时, 处理掉此兼容性
cloud.tencent.com/developer/b…
@FeignClient 注解 不允许接口上使用 @RequestMapping
从使用者的反馈来看这个变更不符合常理, 大家都不太理解为什么要这么做,
从官方提供的回复来看, 认为在 接口上使用 @RequestMapping 有暴露端点的安全隐患, 官方推荐的做法是写在接口上
基于此我们有两个解决方案
- 回退到 springcloud 2020.3, 规避这个问题 -> 基于我们最终还是需要继续往上升级底座版本, 因此这个方案只能临时过渡
- 修改 FeignClient 接口类, 移除 @RequestMapping 注解, 原写于接口上的根路径都移植到了接口方法上
-
- 当我们的写法是依赖上游的 Maven API 时, 这个方案需要上游服务提供方进行代码调整, 需要协作方配合
- 当我们的写法是自定义服务提供方的接口 API 时, 即可自行调整接口类的实现.
Feign RPC 调用出现 UnknownHost 报错
原因是从 SpringCloud 2020 以后官方就移除了 spring-cloud-neflix 的依赖, 其中低版本的 Feign 负载均衡部分使用就有依赖 Robbin, 而新版本的官方推荐使用 Loadbalancer 替代掉 Robbin, 而在 SpringCloudDependency 中官方又没有引入 LoadBalancer 组件, 因此需要在项目中引入, 同时也需要注意 LoadBalancer 的版本需要和 openfeign 保持一致
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
<version>${spring-cloud-starter-loadbalancer.version}</version>
</dependency>
Swagger 启动报错
从 Springboot 2.4 以后, 官方变更了SpringMVC 的路径匹配策略, 因此按照路人给个做法是回滚 spring.mvc.pathmatch.matching-strategy to ant-path-matcher, 并且重写 Springfox WebMvcRequestHandlerProvider
但这种做法毕竟过于临时, 因此我们考虑升级 Swagger 版本至 3.x 版本, 看是否可以解决此问题, 当我们升级完 Swagger3 以后 又发现了如下启动以来问题
Swagger3和SpringBoot搭配,spring-plugin-core报错_蝉沐风的码场的博客-CSDN博客
在研究了 Swagger 最新发展以及 Springboot OpenAPI 等标准集成方案后, 我们发现目前主流的 OpenAPI 已经升级到 V3 的版本
并且市面上也出现了一些与Springboot 最新版本集成的 OpenAPI 门面框架 SpringDoc 和 Knife4j, 这些框架都较于 Swagger 3 与 Springboot 有更好的向后兼容性, 并且 Knife4j 还是国人开发的框架, 其文档友好度十分不错, 也为了后续升级 Springboot 3.x, 我们考虑使用 Knife4j 来替代 Swagger
大家可以参考此篇文章来迁移 Swagger2 到 SpringDoc OpenAPI3, Knife4j 因为是门面框架, 底层是选用的 Springdoc-openapi, 因此可以先迁移后引入 knife4j
另外这里面有几个实际项目的接入后发现的建议点,
- 同时新版 API 注解不支持 Hidden, 因此不能暴露的接口则不需要使用 Tag 注解
- Schema 注解在使用上, 也建议使用 title 定义字段名称, description 定义字段说明, 建议分开填写
@Bean
public OpenAPI cubeRPAOpenAPI() {
return new OpenAPI()
.info(new Info().title("这是个标题")
.description("这是个描述")
.version("这是个版本"))
// 这个一些配置化的组件, 在这里面可以定义全局需要的请求头
.components(components())
// 我们的项目一般是有域名提供服务的, 因此路径是灵活, 因此可以使用 server 这个配置来规避部署后 接口无法直接调用的问题
.servers(Arrays.asList(new Server().url("/context-path").description("API 地址")));
}
private Components components() {
Components components = new Components();
components.addSecuritySchemes(headerName, new SecurityScheme()
.type(SecurityScheme.Type.APIKEY)
.scheme("basic")
.name(headerName)
.in(SecurityScheme.In.HEADER)
.description("鉴权"));
return components;
}
配置文件的建议, 采用 tags-sorter 字母排序, 否则 API 排序混乱, 关闭 doc-expansion 避免打开时默认展开所有 Tag, 导致接口查看繁琐
# springdoc 配置
springdoc:
api-docs:
enabled: true
swagger-ui:
# 使用字母排序
tags-sorter: alpha
# 关闭默认展开Tag
doc-expansion: none
在改造完成后, 再引入 Knife4j Starter 即可
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-spring-boot-starter</artifactId>
<version>4.1.0</version>
</dependency>
简单问题汇总
Springboot @Test 注解 引入报错问题
stackoverflow.com/questions/7…
此问题原因是 Springboot 2.7.x 使用的是 Junit 5.x 版本, 而之前的版本使用的是 Junit 4.x, 这两个版本的 @Test 注解路径不一致, 因此升级代码的注解依赖即可
The old org.junit package is for JUnit 4.x.
The new org.junit.jupiter.api package is for JUnit 5.x.
You should prefer 5.x. JUnit 4.x is old at this point.
Maven 打包出现 Input length = 1 报错问题
此问题的原因是 配置文件出现了 非 UTF-8 字符集 的编码字符, 导致新版本的 Maven-Resource-Plugin 抛出了这个错误, 低版本会容忍掉这个报错, 我们的做法是降级 Maven-Resource-Plugin 的版本为 3.1.0
PS : 我们也可以看实际情况是否可以移除这些 非 UTF-8 的字符, 或者通过插件配置移除这些配置文件的扫描
AsyncConfigurer 配置启动报错问题
此问题的原因是 在异步线程池配置的部分, Springboot 2.7.x 系列已经不需要实现 AsyncConfigurer 类了, 因此移除即可
Failed to instantiate [java.util.concurrent.Executor]: Illegal arguments to factory method 'threadPoolTaskExecutor'; args: ; nested exception is java.lang.IllegalArgumentException: object is not an instance of declaring class
stackoverflow.com/questions/7…
Spring Quatz 启动报错问题
此问题的原因是 Spring-boot-starter-quartz 在 2.5.6 以后更换了默认的数据源, 因此将 Quartz 的数据源切换为以下的即可
org.quartz.jobStore.class=org.springframework.scheduling.quartz.LocalDataSourceJobStore
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'quartzScheduler' defined in class path resource [org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.class]: Invocation of init method failed; nested exception is org.quartz.SchedulerConfigException: DataSource name not set.
Springboot 3.0 升级阻断点预告
Springboot 相关改造
- Javax 迁移 Jarkata 改造
- 配置文件加载逻辑改造
- Bean 自动注入配置改造
- Spring cloud Sleuth 迁移 mircometer 改造
- RPC 服务提供方配置改造
- Hibernate validation 迁移 Jarkata 改造
数据库相关改造
- Mybatis-Plus 3.5.3.1 相关改造
- Durid 自动注入相关改造
转载自:https://juejin.cn/post/7231065366882304058