目录
一、现状
项目正在使用jdk8 如果要升级到jdk17 则需要升级springboot版本及springcloud版本 (springcloud版本和springboot版本必须匹配 要一块升级) 。目前使用的版本如下:
spring boot 版本为 2.1.5.RELEASE
spring cloud 版本为 Greenwich.SR2
spring 版本为 5.1.7.RELEASE
二、升级计划
jdk 由 8 升级到 17
spring boot 由 2.1.5.RELEASE 升级到 2.7.5
spring cloud 由 Greenwich.SR2 升级到 2021.0.5
spring 由 5.1.7.RELEASE 升级到 5.3.22 (自动依赖无需配置)
spring-boot-maven-plugin 升级到 和 springboot版本一致
三、升级注意事项
3.1 介绍
1.jdk8到jdk17版本介绍及升级注意事项
项目中受影响的变化:
JEP 320: Remove the Java EE and CORBA Modules (openjdk.org/jeps/320) 提案,移除了 Java EE and CORBA 的模块
jdk 移除了javax包 可以使用 jakarta.validation-api替代 如果还需要使用 需要maven手动引入依赖jar 比如:javax.validation-api
2.Spring Boot 2.7.x新特性
Spring boot 2.2.x ~ 2.5.x 各版本特性 已停止更新维护
3.Spring Cloud 2021.0.5新特性及升级注意事项
3.1 OpenFeign LoadBalancer
SpringCloud之OpenFeign的常用配置(超时、数据压缩、日志、重试等)
Spring Cloud Feign–解决spring-cloud-loadbalancer的缓存警告
Ribbon 的替代品 Spring Cloud Loadbalancer 使用与原理分析
3.2 Sleuth
解决sleuth链路追踪失效的问题,sleuth版本升级为3.1.3后X-B3-TraceId:-打印不出来了,解决方案
为啥要使用spring-cloud:2021.0.x?
原先使用Hoxton.SR8版本的springcloud,由于Netflix公司宣布其核心组件Hystrix、Ribbon、Zuul、Eureka等进入维护状态,不再进行新特性开发,只修 BUG。而spring官方因此做出应对,在新版本中移除了Netflix
4.Spring Cloud 与Spring Boot 版本对应关系
maven开源仓库版本查看
spring boot dependencies maven仓库
spring cloud dependencies maven仓库
spring cloud & spring boot最新对应关系查看
红色表示已停止维护、已过时 绿色表示可用
注册中心:eureka(停更)、Zookeeper、Consul(go语言编写)、Nacos
服务调用:Ribbon、LoadBalancer(新出的)/ Feign(Netfilx公司不在更新)、OpenFeign(Spring公司自己出的,与Feign相当于葫芦娃兄弟,几乎一样)
服务降级:Hystrix(cloud自带的停更,国内依然很多使用,其思想很值得学习),resilience4j(国外推荐代替Hystrix),sentienl(国内一般推荐用这个,阿里出品)
服务网关:Zuul(内部原因没出Zuul2)gateway(Spring自己推出的)
服务配置:Config,Nacos(把Config替代了)
服务总线:Bus(淘汰) Nacos
3.2 jar包升级
<properties>
<!-- maven build -->
<java.version>17</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven-compiler-plugin.version>3.10.1</maven-compiler-plugin.version>
<maven.javadoc.skip>true</maven.javadoc.skip>
<!-- spring boot -->
<spring-boot.version>2.7.5</spring-boot.version>
<!-- spring cloud -->
<spring-cloud.version>2021.0.5</spring-cloud.version>
<spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version>
<spring-cloud-starter-alibaba-nacos-config.version>2.1.4.RELEASE</spring-cloud-starter-alibaba-nacos-config.version>
</properties>
<dependencies>
<!-- jdk17删除的包引入 -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- 不加会加载不到BootStrap.yml文件 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>${spring-cloud-starter-alibaba-nacos-config.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
</dependencies>
<!-- 管理依赖版本号,子项目不会默认依赖 -->
<dependencyManagement>
<dependencies>
<!-- spring boot 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- spring cloud 依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- spring cloud alibaba 依赖 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
3.3 代码改动
-
还有一些配置类有些方法升级后已经被标识为废弃 这个看情况是否需要改动。
-
Dockerfile配置修改 基础jdk镜像升级 由jdk1.8升级到jdk17 FROM registry.api.xxx.com/bop-k8s/base_image:openjdk17.0.6
openjdk17镜像:
docker pull khipu/openjdk17-alpine:latest
3.4 jenkins 配置修改
1.服务中 JVM 参数配置示例:
JAVA_OPTS=‘-server -XX:+UseG1GC -Xmx2548m -Xss512k -XX:MaxMetaspaceSize=256m -XX:MaxDirectMemorySize=256m -XX:MaxGCPauseMillis=200 -XX:+UnlockExperimentalVMOptions -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/logs/ -Dlog4j2.formatMsgNoLookups=true’ \
docker run 启动参数中 jvm参数在jdk17中已被删除
删除 -XX:+UseCGroupMemoryLimitForHeap
2.报错
Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not “opens java.lang” to unnamed module @5b464ce8
org.springframework.cglib.core.CodeGenerationException: java.lang.reflect.InaccessibleObjectException–>Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not “opens java.lang” to unnamed module @5b464ce8
这是由于 JDK 8 中有关反射相关的功能自从 JDK 9 开始就已经被限制了,为了兼容原先的版本,需要在运行项目时 JVM参数添加 --add-opens java.base/java.lang=ALL-UNNAMED 选项来开启这种默认不被允许的行为。
反射+私有API调用问题
在 Java8 中,没有人能阻止你访问特定的包,比如 sun.misc,对反射也没有限制,只要 setAccessible(true) 就可以了。Java9 模块化以后,一切都变了,只能通过 --add-exports 和 --add-opens 来打破模块封装
–add-opens 导出特定的包
–add-opens 允许模块中特定包的类路径深度反射访问
比如:
–add-opens java.base/java.lang=ALL-UNNAMED
–add-opens java.base/java.io=ALL-UNNAMED
–add-opens java.base/java.math=ALL-UNNAMED
–add-opens java.base/java.net=ALL-UNNAMED
–add-opens java.base/java.nio=ALL-UNNAMED
–add-opens java.base/java.security=ALL-UNNAMED
–add-opens java.base/java.text=ALL-UNNAMED
–add-opens java.base/java.time=ALL-UNNAMED
–add-opens java.base/java.util=ALL-UNNAMED
–add-opens java.base/jdk.internal.access=ALL-UNNAMED
–add-opens java.base/jdk.internal.misc=ALL-UNNAMED
java17启动eureka-server
示例
java -jar --add-exports=java.base/sun.nio.ch=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-exports=jdk.unsupported/sun.misc=ALL-UNNAMED --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED --add-opens=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.text=ALL-UNNAMED --add-opens=java.desktop/java.awt.font=ALL-UNNAMED /Users/fengzy/Documents/git/eureka-server-1.0.0.jar
java17 可能需要依赖的jar包
报错:com/sun/activation/registries/LogSupport
在 pom 文件中引入依赖:
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
异常处理:java.lang.ClassNotFoundException: javax.xml.bind.JAXBContext
在 pom 文件中引入依赖:
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.1</version>
</dependency>