The most comprehensive practical information for upgrading JDK11 to JDK17 is here | JD Cloud technical team

1 Introduction

The previous article brought you the most complete practice of upgrading JDK8 to JDK11. I believe that you will have a deeper understanding of JDK11 after reading it. On September 14, 2021, Oracle released the JDK17 version that can be supported for a long time. So what features are brought from JDK11 to JDK17? What is the effect of sub-millisecond ZGC? Is it worth upgrading? And what problems will you encounter during the upgrade process? With these questions in mind, this article will bring the most complete practice of upgrading JDK11 to JDK17.

2. Why upgrade to JDK17?

1) Long-term support version

JDK17 is a long-term support (LTS) version officially released by Oracle on September 14, 2021, which means that it will receive long-term updates and support, helping to maintain the stability and reliability of the program.

2) Performance improvement

Better garbage collector. Comprehensive evaluation, after upgrading from Java 8 to Java 11, the average speed of **G1GC increased by 16.1% and ParallelGC by 4.5%****. **Upgrading from Java 11 to Java 17, the average speed of G1GC increased by 8.66% and ParallelGC by 6.54 % ( Use case benchmarking based on OptaPlanner shows)

The biggest highlight is the introduction of a stable version of the ZGC garbage collector, which achieves sub-millisecond pauses.

3) New syntax and features

Switch expression simplification, Text Blocks text blocks, instanceof pattern matching upgrade and NullPointerException prompt information improvement, etc.

4) Support the latest technologies and frameworks

Spring framework6 and Spring Boot3 both use Java 17 as the minimum version by default

3. Pressure test results after upgrade

Let’s give the conclusion first:

1. Compared with JDK8 and JDK11, the performance of all garbage collectors in JDK17 has been significantly improved, especially the stable version of the ZGC garbage collector.

2. Regardless of the machine configuration, it is recommended to use ZGC . The pause time of ZGC reaches sub-millisecond level and the throughput is relatively high.

I chose machines with different configurations (2C4G, 4C8G, 8C16G) on the JDOS platform, and used JDK8, JDK11 and JDK17 respectively for deployment and stress testing.

The entire stress test process is limited to 60 minutes, and 180 virtual users are used to concurrently request an interface. Each interface request creates 512Kb of data. Finally, various indicator data of different GC collectors are output to analyze the performance improvement effect of GC.

The following is the performance of the pressure test:

4. Choice of OracleJDK and OpenJDK

In September 2021, Oracle announced that JDK17 will be free for commercial use and will continue to be available for a full year after the next LTS version. At the same time, Oracle will continue to provide Oracle OpenJDK versions under the GPL according to the same versions and schedule since Java 9.

In September 2023, OracleJDK released a new LTS version JDK21, which means that starting from September 2024, you will need to pay to use OracleJDK17 in a production environment.

Reference: https://www.oracle.com/hk/java/technologies/downloads/#java17

There are no real technical differences between the two, OracleJDK and OpenJDK, because the build process for Oracle JDK is based on OpenJDK. Since JDK11, OracleJDK and OpenJDK have basically the same functionality, so it is recommended to use OpenJDK17 or other open source JDK versions. These open source versions are built based on OpenJDK and provide long-term support, such as: AdoptOpenJDK , RedHatOpenJDK.

Official reference: https://blogs.oracle.com/java/post/oracle-jdk-releases-for-java-11-and-later

5. What new features have been brought by JDK11 to JDK17?

5.1. JVM improvements

1. The ZGC garbage collector has been changed from an experimental function to a formal product function . Since the introduction of JDK11, it has been stable enough after continuous iterative upgrades. Need to be turned on manually, turning on method: -XX:+UseZGC

2. The G1 garbage collector is still the default garbage collector and has been improved and upgraded, mainly including abortable mixed collection sets, NUMA-aware memory allocation, etc.

3. JDK14 starts to delete CMS garbage collector

4. JDK14 begins to deprecate the combined use of ParallelScavenge and SerialOld GC

5. JDK15 disables biased locking, disabled by default: -XX:+UseBiasedLocking

6. NullPointerException prompt information improvement

When a NullPointerException occurs before JDK14, you can only locate the exception line, but cannot locate the specific variable. The improved NullPointerException can clearly describe specific variables and improves the readability of null pointer exceptions.

5.2. New syntax features

5.2.1. Simplification of Switch expression

The switch expression brings a simplified coding method and provides a new branch switching method, that is, the -> symbol. The expression method body on the right automatically ends the switch branch after executing the branch method, and the -> method block on the right It can be an expression, a code block, or a manually thrown exception.

Reference: https://openjdk.org/jeps/361

traditional writing

New way of writing

5.2.2. Text Blocks text blocks

Reference: https://openjdk.org/jeps/378

By writing """, escape characters and newlines are reduced to simplify the code and improve the readability of the code.

5.2.3. Record type

Reference: https://openjdk.org/jeps/395

record is a keyword introduced in JDK 14 for declaring immutable data classes. It is suitable for storing pure value type data, such as interface transmission data, coordinate points and read-only log records. Compared with lombok, record simplifies the process of defining pure data types. Since the record class is immutable, member variables can only be set once and cannot be changed without providing an explicit setter() method.

1. Define the Point class, use the keyword record, and get/set is not defined.

2. View the compiled bytecode file

3. Use the Point class

5.2.4. Pattern matching upgrade of instanceof

  • Instanceof type judgment no longer requires cast

Reference: https://openjdk.org/jeps/394

5.2.5. Sealed classes and interfaces

Reference: https://openjdk.org/jeps/409

Starting from JDK15, sealed ordinary classes or interface classes were introduced. These classes only allow the specified class or interface to be extended and implemented.

Using the modifier sealed, you can declare a class as sealed. A sealed class uses the permits keyword to list classes that can directly extend it. Subclasses can be final, unsealed or sealed

A more practical feature that can be used to limit the class hierarchy

5.2.6. Other optimizations and upgrades

Interested students are recommended to read the official documentation of OpenJDK, changes from JDK11 to JDK17: https://openjdk.org/projects/jdk/17/jeps-since-jdk-11

6. Upgrade steps

6.1. JDK selection

OpenJDK17 download: https://jdk.java.net/archive/

Xingyun image: jdt-base-tomcat/java-jdt-centos7.4-openjdk-17.0.2-tomcat8.0.53

6.2. pom compilation configuration upgrade

The JDK required for maven compilation is upgraded to 17

<properties>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
</properties>

6.3. SpringBoot upgrade

The SpringBoot version is upgraded to 2.7.15 and the Spring version is upgraded to 5.3.29

Why not upgrade to SpringBoot3?

Spring Boot 3.0 requires Java 17 as a minimum. Spring Boot 3.0 has brought many changes, which are quite different from Spring Boot 2. Considering that many of the company's middleware are built based on SpringBoot2, it is recommended to upgrade to the highest version of SpringBoot2, 2.7.15.

POM upgrade

<parent>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-parent</artifactId>
 <version>2.7.15</version>
</parent>

You can also set dependencyManagement:

<properties>
    <!-- 框架版本配置-->
    <springboot-version>2.7.15</springboot-version>
    <springframework.version>5.3.29</springframework.version>
</properties>  

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>${springboot-version}</version>
            <scope>import</scope>
            <type>pom</type>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-framework-bom</artifactId>
            <version>${springframework.version}</version>
            <scope>import</scope>
            <type>pom</type>
        </dependency>
    </dependencies>
</dependencyManagement>

reference:

Spring upgrade guide: https://github.com/spring-projects/spring-framework/wiki/Spring-Framework-Versions

Springboot version official website: https://spring.io/projects/spring-boot#learn

circular dependency problem

After SpringBoot is upgraded to 2.7.15, if there is a circular dependency problem in the application, the following error will be reported when starting:

Reason : Official documentation discourages circular dependency references and is prohibited by default

solution:

The first one: It is recommended to update the dependencies of beans in the application to solve the problem.

Second type: Add the following configuration to the configuration file. In order to be consistent with the old version, it is recommended to add this configuration.

#放开循环依赖
spring.main.allow-circular-references=true

6.4. Common middleware upgrades

6.4.1, Lombok version upgraded to 1.18.20 or above

<dependency>
 <groupId>org.projectlombok</groupId>
 <artifactId>lombok</artifactId>
 <version>1.18.20</version>
</dependency>

If you do not upgrade, the following error will be reported during compilation:

6.4.2, swgger problem, springfox3.0.0 and springboot2.7 versions are incompatible

abnormal:

Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException: 
Cannot invoke "org.springframework.web.servlet.mvc.condition.PatternsRequestCondition.getPatterns()" because "this.condition" is null

solution:

/**
 * 增加如下配置可解决Spring Boot 2.7.15 与Swagger 3.0.0 不兼容问题
 **/
@Bean
public BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {
return new BeanPostProcessor() {

@Override
 public 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);
            }
        }
    };
}

Reference: https://developer.aliyun.com/article/950787

6.4.3. AKS upgrade (for direct upgrade from JDK8)

异常:Causedby: java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException

Reason : Java11 deleted Java EE modules, including java.xml.bind (JAXB).

solution:

Simply import the following packages manually

<!-- API, java.xml.bind module --> 
<dependency>
      <groupId>jakarta.xml.bind</groupId>
      <artifactId>jakarta.xml.bind-api</artifactId>
      <version>2.3.2</version>
</dependency> 
<!-- Runtime, com.sun.xml.bind module -->
<dependency>
       <groupId>org.glassfish.jaxb</groupId>
       <artifactId>jaxb-runtime</artifactId>
       <version>2.3.2</version>
</dependency>

6.4.4. Concrete configuration center blocks upgrade

When using Concrete, exception on startup:

 Unable to make field private static final java.lang.reflect.Method jdk.proxy2.$Proxy97.m0 accessible: 
 module jdk.proxy2 does not "opens jdk.proxy2" to unnamed module @61d47554

reason:

Analyze the reason why Concrete reports an error, as shown below, the implementation logic of com.wangyin.concrete.spring.ConcreteConfigProcessor#postProcessAfterInitialization (line 212) in the package

solution:

1. Set --add-opens jdk.proxy2 in the JVM startup parameters to enable access to private fields. However, because the package name generated by the dynamic proxy is random and unclear, this solution is not feasible . The official JDK documentation also clearly states that accessing random fields inside dynamic proxies is not supported. Official description: https://cr.openjdk.org/~mr/jigsaw/spec/api/java/lang/reflect/Proxy.html

2. To modify the code, just move f.setAccessible(true) below the judgment of Modifier.isStatic(f.getModifiers()). The reason is that the method Modifier.isStatic(f.getModifiers()) originally skips the static fields, so the modification directly avoids access. Push concrete team to fix issues or replace using Ducc Configuration Center

6.5. JVM startup parameter configuration

6.5.1. Start ZGC

Configuration in startup parameters: -XX:+UseZGC

Remove -XX:ConcGCThreads, JVM parameter configuration needs to be cleared under cloud deployment

6.5.2. Startup parameters required for different middleware

After upgrading JDK17, you may encounter the following two types of exceptions when starting the project:

1、cannot access class sun.util.calendar.ZoneInfo (in module java.base) because module java.base does not export sun.util.calendar to unnamed module @0x2611f533

2、Unable to make field final int java.math.BigInteger.signum accessible: module java.base does not "opens java.math" to unnamed module @525f1e4e

Abnormal reason:

Since the modular function was introduced in JDK9, and then in JDK17, the permission control for packet scanning and reflection has become more stringent. Common libraries such as (Spring) make extensive use of packet scanning and reflection, so this error often occurs.

solution:

A crude solution is to force unopened modules to be open to the outside world, that is, to keep them consistent with the versions before Java 9.

  • --add-exports exports the package, meaning that all public types and members in it can be accessed at compile and run time.
  • --add-opens opens the package, meaning that all types and members in it (not just public types) are accessible at runtime.

The main difference is that --add-opens"deep reflection" is allowed, that is, access to non-public members can be calledsetAccessible(true)

Reference: https://stackoverflow.com/questions/44056405/whats-the-difference-between-add-exports-and-add-opens-in-java-9

SGM needs to join:

--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

R2M needs to join:

--add-opens java.base/java.time=ALL-UNNAMED

Ducc needs to join:

--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 

AKS needs to join:

--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

6.6. Verification after startup

1. It is recommended to upgrade to JDK11 first, then to JDK17, and conduct verification and observation while upgrading.

2. Observe the logs for any abnormalities, especially the startup exceptions mentioned above.

3. Observe monitoring software, such as SGM, UMP, etc., to see if monitoring is normal.

4. It is recommended to gradually and orderly cut the volume and conduct normalized stress testing to prevent impact on the core business.

5. After the upgrade is completed, it is best to conduct a full-process functional test to prevent functional abnormalities.

7. Summary

1. After the upgrade, in addition to using new syntax features, the biggest highlight is the GC performance that can use sub-millisecond pauses (at least a hundred times GC performance improvement), so it is strongly recommended to upgrade to JDK17

2. The entire upgrade process is not complicated and mainly involves the upgrade of the middleware version and the configuration of startup parameters.

If you are still stuck in JDK8, it is recommended to upgrade to JDK11 first, and then to JDK17. For specific upgrade steps, please refer to my previous article " JDK8 Upgrade JDK11 The Most Comprehensive Practical Tips ", and then refer to the upgrade steps in this chapter.

I hope the above sharing can bring practical help to everyone. If you encounter any problems during the upgrade process, you are welcome to reply in the comment area.

Author: Jingdong Technology Qu Zhenfu

Source: JD Cloud Developer Community Please indicate the source when reprinting

Alibaba Cloud suffered a serious failure and all products were affected (restored). Tumblr cooled down the Russian operating system Aurora OS 5.0. New UI unveiled Delphi 12 & C++ Builder 12, RAD Studio 12. Many Internet companies urgently recruit Hongmeng programmers. UNIX time is about to enter the 1.7 billion era (already entered). Meituan recruits troops and plans to develop the Hongmeng system App. Amazon develops a Linux-based operating system to get rid of Android's dependence on .NET 8 on Linux. The independent size is reduced by 50%. FFmpeg 6.1 "Heaviside" is released
{{o.name}}
{{m.name}}

Guess you like

Origin my.oschina.net/u/4090830/blog/10142895