性能加速包:SpringBoot 2.7&JDK 17,你敢尝一尝吗

Tech 导读
本文将探讨如何通过结合使用SpringBoot 2.7和JDK 17来优化和加速Java应用的性能。通过分析SpringBoot的新特性和改进,以及JDK 17的性能提升点,讨论它们如何协同工作,为Java开发者带来更高效的编程体验。本文还将涉及迁移现有应用至这一新环境的可能挑战和注意事项,为那些追求最前沿技术的勇敢尝试者提供实践建议。
导读
本文将探讨如何通过结合使用SpringBoot 2.7和JDK 17来优化和加速Java应用的性能。通过分析SpringBoot的新特性和改进,以及JDK 17的性能提升点,讨论它们如何协同工作,为Java开发者带来更高效的编程体验。本文还将涉及迁移现有应用至这一新环境的可能挑战和注意事项,为那些追求最前沿技术的勇敢尝试者提供实践建议。
众所周知,SpringBoot3.0迎来了全面支持JDK17的局面,且最低支持版本就是JDK17,这就意味着,Spring社区将完全抛弃JDK8,全面转战JDK17。作为JAVA开源生态里的扛把子,Spring可以说是整个JAVA生态的风向标,可以说,当Spring转战JDK17,会很快带领JAVA生态全面的跟进JDK17。而本篇文章重点讲述Spring版本和JDK17升级中的实践整理。
If you’re currently running with an earlier version of Spring Boot, we strongly recommend that you upgrade to Spring Boot 2.7 before migrating to Spring Boot 3.0.关于JDK17的新特性和优势,对于它支持的新语法和编程特性,此处不再赘述。
落地JDK17的动力主要源于两个方面:一是更为安全的语言特性,二是更加优异的垃圾回收器和性能提升。
3.1 安全的语言特性
3.2 垃圾收集器
JDK17引入了ZGC作为垃圾收集器,此处引用一下京东科技的曲振富做的关于不同垃圾收集器在不同JDK版本下的压测结果:
图 1.
压测服务背景:
3.3 OpenJDK17下载地址
本文为读者提供了一个OpenJDK17的下载地址:
https://adoptium.net/zh-cn/temurin/releases/?version=17&os=linux&arch=x64
4.1 Spring Boot 2.7
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.jd.magnus</groupId><artifactId>magnus-multi-ddd</artifactId><version>1.0.0-SNAPSHOT</version><packaging>pom</packaging><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.17</version></parent><modules><module>magnus-multi-ddd-adapter</module><module>magnus-multi-ddd-application</module><module>magnus-multi-ddd-domain</module><module>magnus-multi-ddd-infrastructure</module><module>magnus-multi-ddd-client</module><module>magnus-multi-ddd-worker</module></modules><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><jsf-lite.version>1.0.0-HOTFIX-T2</jsf-lite.version><ump.version>20221231.1</ump.version></properties></project>
4.1.2. 动态配置
Spring Boot 2.7对动态配置进行了更新。具体来说,Spring Boot 2.7更改了自动配置注册文件的路径和格式,从META-INF/spring.factories变更为META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports。
同时,Spring Boot 2.7还引入了新的注解@SpringBootApplication,该注解包含了@EnableAutoConfiguration和@ComponentScan等注解,使得配置更加简洁和方便。此外,Spring Boot 2.7还更新了一些自动配置的类和方法,以支持新版本的Spring Framework和Java。
1.废弃的方法和类删除。列一下主要删除的方法和类:
SpringBootServletInitializer:在Spring Boot 2.7中,该类已经被移除,建议使用SpringBootServletWebServerApplicationContext来代替。ServletWebServerFactoryCustomizer:这个接口已经从Spring Boot 2.7中移除,可以使用WebServerFactoryCustomizer来代替。BasicErrorController:这个类已经从Spring Boot 2.7中移除,可以使用ErrorController接口来代替。ContentNegotiationStrategy:这个接口已经从Spring Boot 2.7中移除,可以使用RequestMappingHandlerMapping的setContentTypeResolver(ContentTypeResolver)方法来代替。HttpMessageConverters:这个接口已经从Spring Boot 2.7中移除,可以使用HttpMessageConvertingComparator来代替。HttpMessageConvertingComparator:这个类已经从Spring Boot 2.7中移除,可以使用ComparatorChain来代替。ServletWebServerFactoryCustomizerBeanPostProcessor:这个类已经从Spring Boot 2.7中移除。SpringBootApplicationContextLoader:这个类已经从Spring Boot 2.7中移除,可以使用SpringApplicationWebApplicationContext来代替。SpringBootServletInitializerAutoConfiguration:这个类已经从Spring Boot 2.7中移除,可以使用SpringBootServletWebServerApplicationContextAutoConfiguration来代替。
github上的release版本说明:
4.1.3. 单元测试升级
| 变更项 | JUnit4 | JUnit Jupiter |
| @Test注解 | 包路径:org.junit.Test | 包路径:org.junit.jupiter.api.Test |
| 断言 | 类:org.junit.Assert | 类:rg.junit.jupiter.api.Assertions,提供了更简洁的断言方法 |
| @RunWith | 需要使用@RunWith注解来指定测试运行器 | @RunWith移除,不再需要,单侧只需要@SpringBootTest |
| 参数化接口测试 | @RunWith配合 @Parameters实现参数化 | @ParameterizedTest和@ValueSource注解配合使用 |
4.1.4. hibernate-validator包依赖问题
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-properties-migrator</artifactId><scope>runtime</scope></dependency>
4.2 行云部署配置
首先需要新的基础镜像包,包括OpenJDK17的。之前行云的镜像市场上是没有相关的镜像的,后来联系科技运维同事帮忙制作了新的镜像,新的镜像包是基于Tomcat应用类型的,大家可以在jdos的中国站的景象市场搜索到。镜像名如下,
base_tomcat/java-jd-centos7-jdk17-tomcat8.5.42-ngx197:latest图 2.
然后就是配置JVM启动参数,需要开启ZGC。具体启动参数以4C8G的资源为例,配置参数如下:
-Xms5324m -Xmx5324m -XX:MaxMetaspaceSize=256m -XX:MetaspaceSize=256m -XX:MaxDirectMemorySize=983m-Djava.library.path=/usr/local/lib -server -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/export/Logs-Djava.awt.headless=true -Dsun.net.client.defaultConnectTimeout=60000 -Dsun.net.client.defaultReadTimeout=60000-Djmagick.systemclassloader=no -Dnetworkaddress.cache.ttl=300 -Dsun.net.inetaddr.ttl=300-XX:+UseZGC
此处需要注意,ZGC不要配置并行GC线程的数量,并发标记线程数等信息,配置了反而会出现启动报错情况。
4.3 兼容性问题说明
--add-opens java.base/sun.security.action=ALL-UNNAMED--add-opens java.base/java.lang=ALL-UNNAMED--add-opens java.base/java.math=ALL-UNNAMED--add-opens java.base/java.util=ALL-UNNAMED--add-opens java.base/sun.util.calendar=ALL-UNNAMED--add-opens java.base/java.util.concurrent=ALL-UNNAMED--add-opens java.base/java.util.concurrent.locks=ALL-UNNAMED--add-opens java.base/java.security=ALL-UNNAMED--add-opens java.base/jdk.internal.loader=ALL-UNNAMED--add-opens java.management/com.sun.jmx.mbeanserver=ALL-UNNAMED--add-opens java.base/java.net=ALL-UNNAMED--add-opens java.base/sun.nio.ch=ALL-UNNAMED--add-opens java.management/java.lang.management=ALL-UNNAMED--add-opens jdk.management/com.sun.management.internal=ALL-UNNAMED--add-opens java.management/sun.management=ALL-UNNAMED--add-opens java.base/sun.security.action=ALL-UNNAMED--add-opens java.base/sun.net.util=ALL-UNNAMED--add-opens java.base/java.time=ALL-UNNAMED--add-opens java.base/java.io=ALL-UNNAMED
1. SGM依赖需要加入
--add-opens java.management/java.lang.management=ALL-UNNAMED--add-opens jdk.management/com.sun.management.internal=ALL-UNNAMED--add-opens java.management/sun.management=ALL-UNNAMED
2. R2M需要加入
--add-opens java.base/java.time=ALL-UNNAMED3. DUCC依赖需要加入
--add-opens java.base/java.util.concurrent=ALL-UNNAMED--add-opens java.base/java.util.concurrent.locks=ALL-UNNAMED--add-opens java.base/java.security=ALL-UNNAMED--add-opens java.base/jdk.internal.loader=ALL-UNNAMED--add-opens java.management/com.sun.jmx.mbeanserver=ALL-UNNAMED--add-opens java.base/java.net=ALL-UNNAMED--add-opens java.base/sun.nio.ch=ALL-UNNAMED
4. AKS依赖需要加入
--add-exports java.base/sun.security.action=ALL-UNNAMED--add-opens java.base/java.lang=ALL-UNNAMED--add-opens java.base/java.math=ALL-UNNAMED--add-opens java.base/java.util=ALL-UNNAMED--add-opens java.base/sun.util.calendar=ALL-UNNAMED
5. Pfinder依赖需要加入
--add-opens java.base/sun.net.util=ALL-UNNAMED6. jsf依赖需要加入
--add-opens java.base/java.time=ALL-UNNAMED #当使用LacalDate做出入参时需要添加--add-opens java.base/java.io=ALL-UNNAMED7. Swagger兼容性配置
spring.mvc.pathmatch.matching-strategy=ant_path_matcher/*** 增加如下配置可解决Spring Boot 2.7.15 与Swagger 3.0.0 不兼容问题**/@Beanpublic BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {return new BeanPostProcessor() {@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (bean instanceof WebMvcRequestHandlerProvider || bean instanceof WebFluxRequestHandlerProvider) {customizeSpringfoxHandlerMappings(getHandlerMappings(bean));}return bean;}private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(List<T> mappings) {List<T> copy = mappings.stream().filter(mapping -> mapping.getPatternParser() == null).collect(Collectors.toList());mappings.clear();mappings.addAll(copy);}@SuppressWarnings("unchecked")private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) {try {Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");field.setAccessible(true);return (List<RequestMappingInfoHandlerMapping>) field.get(bean);} catch (IllegalArgumentException | IllegalAccessException e) {throw new IllegalStateException(e);}}};}
| 类名 | 方法说明 |
| javafx.util.Pair | getKey():获取 Pair 对象的键。getValue():获取 Pair 对象的值。setKey(K key):设置 Pair 对象的键。setValue(V value):设置 Pair 对象的值。 |
| avafx.util.Duration | toSeconds():将持续时间转换为秒。toMillis():将持续时间转换为毫秒。toNanos():将持续时间转换为纳秒。add(Duration other):将另一个持续时间添加到当前持续时间。subtract(Duration other):从当前持续时间中减去另一个持续时间。 |
| javafx.util.converter | fromString(String value):将字符串值转换为目标类型。toString(T value):将目标类型的值转换为字符串。 |
| javafx.util.StringConverter | fromString(String value):将字符串值转换为目标类型。toString(T value):将目标类型的值转换为字符串。 |
关于JSF启动有报错信息:运行时找不到 javax.xml.bind.JAXBException 类。在 JDK 9 及更高版本中,javax.xml.bind 包被移除了,并且不再包含在标准的 Java SE 中。如果您的项目依赖于 JAXB API,您可以尝试以下解决方法之一:如果您使用的是 JDK 8 或更早版本,请确保您的项目使用的是兼容的 JDK 版本。如果您使用的是 JDK 9 或更高版本,并且需要使用 JAXB API,您可以添加以下依赖项来解决该问题:<dependency><groupId>jakarta.xml.bind</groupId><artifactId>jakarta.xml.bind-api</artifactId><version>3.0.1</version> <!-- 根据您的需求选择合适的版本 --></dependency>
| module | packages | replacement groupld | replacement artifactld |
| java.activation | javax.activtion | com.sun.activation | jakarta.activation |
| java.xml.ws.annotation | java.annotation | jakartaa.annotation | jakarta.annotation-api |
| java.xml.bind | javax.xml.bind.* | jakarta.xml.bind.com.sun.xml.bind | jakarta.xml.bind-apijab-impl |
除此之外,JSF在使用ForkJoinPool会导致反序列化问题,包括底层使用ForkJoinPool的CompletableFuture.runAsync 有同样问题。原因是升级JDK后,jsf依赖了jaxb包在新JDK中是缺失的,会导致注册中心自动切换有问题,解决方案是手动引入如下包:
<dependency><groupId>javax.xml.bind</groupId><artifactId>jaxb-api</artifactId><version>2.2.8</version></dependency><dependency><groupId>com.sun.xml.bind</groupId><artifactId>jaxb-core</artifactId><version>2.2.8</version></dependency><dependency><groupId>com.sun.xml.bind</groupId><artifactId>jaxb-impl</artifactId><version>2.2.8</version></dependency><dependency><groupId>javax.activation</groupId><artifactId>activation</artifactId><version>1.1.1</version></dependency>
目前最的DDD脚手架已经支持Spring Boot 2.7.17 和JDK17 ,下载脚本如下:
mvn archetype:generate \-DarchetypeGroupId=com.jd.magnus \-DarchetypeArtifactId=magnus-multi-ddd-archetype \-DarchetypeVersion=1.0.0-SNAPSHOT \-DinteractiveMode=false \-DarchetypeCatalog=remote \-Dversion=1.0.0-SNAPSHOT \-DgroupId=com.jdl.sps \-DartifactId=bff-demo1
该脚手架以在京东内部申请为开源项目,开源项目地址如下:
http://xingyun.jd.com/shendeng/openSource/detail/793
求分享
求点赞
求在看
▪功能支撑:会员成长体系、等级计算策略、权益体系、营销底层能力支持
▪用户活跃:会员关怀、用户触达、活跃活动、业务线交叉获客、拉新促活