JDK8升级JDK11最全实践干货来了
截至目前(2023年),Java8发布至今已有9年,2018年9月25日,Oracle发布了Java11,这是Java8之后的首个LTS版本。那么从JDK8到JDK11,到底带来了哪些特性呢?值得升级吗?而且升级过程会遇到哪些问题呢?带着这些问题,本篇文章将带来完整的JDK8升级JDK11最全实践。
一、为什么升级JDK11
【 1.1 性能提升 】 更好的垃圾收机制、更快的类加载器,加快应用程序的运行速度。综合评估,从Java 8 升级到 Java 11,G1GC平均速度提升16.1%,ParallelGC为4.5%(基于OptaPlanner的用例基准测试表明https://www.optaplanner.org/blog/2019/01/17/HowMuchFasterIsJava11.html)。
截至目前(2023年),Java8发布至今已有9年,2018年9月25日,Oracle发布了Java11,这是Java8之后的首个LTS版本。那么从JDK8到JDK11,到底带来了哪些特性呢?值得升级吗?而且升级过程会遇到哪些问题呢?带着这些问题,本篇文章将带来完整的JDK8升级JDK11最全实践。
一、为什么升级JDK11
更好的垃圾收机制、更快的类加载器,加快应用程序的运行速度。综合评估,从Java 8 升级到 Java 11,G1GC平均速度提升16.1%,ParallelGC为4.5%(基于OptaPlanner的用例基准测试表明https://www.optaplanner.org/blog/2019/01/17/HowMuchFasterIsJava11.html)。
【 1.2 特性和改进 】
局部变类型推断、新的 API、HTTP/2客户端、Lambda表达式的新特性等,这些新特性可以提高开发效率。
【 1.3 支持最新的技术和框架 】
许多新的技术和框架已经或即将开始依赖于JDK11或以上版本,升级后可以保证应用程序能够分利用这些新的技术和框架。
【 1.4 长期支持版本 】
JDK11是Oracle官方发布的一个长期支持(LTS),意味着它将获得长期的更新和支持,有助于保持用程序的稳定性和可靠性。
【 1.5 行业趋势 】
数据来自 New Relic (https://newrelic.com/resources/report/2023-state-of-the-java-ecosystem)在2023年1月发布的Java生态报告,从下图可以看出:
目前市面上有超过 56%的应用程序使用了JDK 11,Java 8 的使用从2020年的84%降低到了现在的32%左右。大部分公司在这三年之间都升级到了JDK 11 或者 JDK 17这两个LTS版本上面。
垃圾收集器使用情况来看,JDK11版本及以上G1使用率最高,占比高达65%。
二、升级后GC效果
1、JDK11相对于JDK8,所有垃圾回收器的性能都有提升,特别是大内存机器下G1的提升最明显;
在JDOS平台上选择了不同配置的机器(2C4G、4C8G、8C16G),并分别使用JDK8和JDK11进行部署和压测。
整个压测过程限时60分钟,用180个虚拟用户并发请求一个接口,每次接口请求都创建512Kb的数据。最终产出不同GC回收器的各项指标数据,来分析GC的性能提升效果。
* 上面给出的GC升级效果,采用的是默认的配置,没有做任何优化,只提供参考。真正的GC调优是个技术活,需要根据业务需求、机器配置和实际压测效果等综合评估来选出最合适的GC垃圾回收器。
三、JDK11带来了哪些新特性
【 3.1 GC改进 】
G1特点:目标是降低应用程序的停顿时间并提高吞吐量。
引入ZGC垃圾回收器(可伸缩低延迟垃圾收集器);但由于JDK11中ZGC还不够完善,推荐在JDK17中再使用稳定版ZGC
Full GC的停顿不超过10毫秒 支持TB级堆内存回收 相对于G1吞吐量下降不超过15%
【 3.2 模块化 】
Java9引入了对于模块化软件支持,而Java11进一步扩展了这种特性。模块化让应用程序更精简,减少对其他类库的依赖和冗余代码,提高运行效率和安全性。
【 3.3 语法增强 】
局部变量推断,引入var局部变量类型,允许开发人员省略通常不必要的局部变量类型初始化声明
图3.
Lambda表达式简化,内部可以使用var
图4.
接口中可以定义私有方法,可以实现接口方法的访问控制和代码复用
图5.
【 3.4 API增强 】
HTTPClient标准化支持:强大而灵活的HTTP客户端API,支持多协议(HTTP/2、WebSocket)、异步非阻塞、流操作和连接池等特性。ps:再也不需要用第三包 HttpClient 工具包
字符串方法增强:
isBlank、lines、strip、stripLeading、stripTrailing和repeatFiles增强:readString、WriteString
InputStream增强:transferTo(流快速拷贝)
stream增强,dropWhile(从集合中删除满足的)、takeWhile(从集合中获取满足的)、ofNullable
集合工厂方法:Sets.of()、List.of()、Map.of()、Map.ofEntries(),举例:List<String> list = List.of("Java", "Python", "C++")
四、如何升级
【 4.1 升级应用评估 】
为保证稳定性,优先在新业务新应用来落地实施JDK11的升级。
【 4.2 JDK选择 】
【 4.3 GC配置 】
G1垃圾回收器(JDK11默认,不需要手动配置):-XX:+UseG1GC Parallel GC垃圾回收器:XX:+UseParallelGC
【 4.4 升级过程踩坑 】
【 4.5 升级后验证 】
升级后完成,做好单测和回归测试,推荐能做个压测验证,防止影响线上服务稳定性。
五、新特性实践-模块化
【 5.1 模块化是什么 】
模块化指的是JAVA平台的模块系统(Java Platform Module System),简称JPMS。JPMS引入一种新方式来组织和构建Java应用程序,它将代码分为相互独立、可复用的模块。每个块都有自己的命名空间,明确声明并控制其他模块的访问权限。这种模块化设计使得开发人员能够更好地维护复杂的应用程序,提高代码的复用性、可维护性和安全性,同时提升应用的加载速度和性能。最大的特点是可以定义模块描述符来隔离module(Jar包)内部类的访问权限。
模块化的几点关键说明:
JDK9以后引入了一个新组件module:模块描述符module-info.java,用于将一组相关的包放入一个组中。 在Java8和更早的应用程序中,应用程序将包作为顶级组件,Java9以后应用程序将模块作为顶级组件。 一个模块(Jar包)只能有一个module-info.java。
图6、7.
【 5.2 带来了哪些好处 】
【 5.3 如何使用 】
包结构如下:
com.jdt.apersonMen.javareflectReflectModel.javamodule-info.java
module module.a {//指令用于指定一个模块中哪些包下的public对外是可访问的,包括直接引入和反射使用exports com.jdt.a.person;// 只能被反射调用,用于指定某个包下所有的类(公开、非公开)都只能在运行时可被别的模块进行反射访问。opens com.jdt.a.refect;}
2)定义module-b.jar,包的pom中指定依赖了module-a
包结构如下:
com.jdt.btestTest.javamodule-info.java
module module.b {//依赖a下的包requires module.a;}
图8.
【 5.4 实践过程的坑 】
1)依赖JSF包时无法模块化
进行模块化时,pom中依赖了jsf包,模块定义如下:
module module.a {requires fastjson;//依赖jsf包名requires jsf.lite;exports com.jd.jdk.test.module;}
图9.
问题原因:
经过一系列定位研究,发现jsf-lite包中,/META-INF/services下的文件org.glassfish.jersey.internal.spi.AutoDiscoverable里面写的类是com.alibaba.fastjson.support.jaxrs.FastJsonAutoDiscoverable,此类并未在当前jsf.lite包中定义,属于com.alibaba.fastjson包的。
图10.
解决方案:
例如:
module-a.jar包结构定义:com.foo.packageA.javamodule-b.jar包结构定义:com.foo.packageB.java
当module-c同时依赖module-a和module-b时,如上编译时会报一个错,Package com.foo.package in both module module.b and module module.a,这就是JAVA9的模块隔离,要求只能从一个模块(module)中读取同一个包(package),不能跨模块读取。
解决方案:
【 5.5 模块化落地总结 】
目前不推荐使用模块化,因为相关组件生态还不完善,并且模块化带来的价值不够突出:
1.很多中间件都是基于jdk8构建的,都有可能遇到模块化兼容的问题,比如:jsf,需要jsf强制升级才可以使用模块化;
2.拆包问题无法解决,比如:aws-java-sdk-s3、fluent等。
六、总结
1、升级过程简单,升级后可以使用更多新特性和更好的GC性能,所以建议升级到JDK11。
2、现阶段不推荐使用模块化,但是不用担心会影响JDK11的升级。
希望以上分享可以给大家带来实际的帮助。
▪功能支撑:会员成长体系、等级计算策略、权益体系、营销底层能力支持
▪用户活跃:会员关怀、用户触达、活跃活动、业务线交叉获客、拉新促活