乐清网站制作推荐,新产品代理,中企动力重庆分公司怎么样,今科网站建设怎么样1、前言
截至目前#xff08;2023年#xff09;#xff0c;Java8发布至今已有9年#xff0c;2018年9月25日#xff0c;Oracle发布了Java11#xff0c;这是Java8之后的首个LTS版本。那么从JDK8到JDK11#xff0c;到底带来了哪些特性呢#xff1f;值得我们升级吗#x…1、前言
截至目前2023年Java8发布至今已有9年2018年9月25日Oracle发布了Java11这是Java8之后的首个LTS版本。那么从JDK8到JDK11到底带来了哪些特性呢值得我们升级吗而且升级过程会遇到哪些问题呢带着这些问题本篇文章将带来完整的JDK8升级JDK11最全实践。
2、为什么升级JDK11
1性能提升
更好的垃圾收机制、更快的类加载器, 加快应用程序的运行速度。综合评估从Java 8 升级到 Java 11G1GC平均速度提升16.1%ParallelGC为4.5%基于OptaPlanner的用例基准测试表明
2特性和改进
局部变类型推断、新的 API、HTTP/2客户端、Lambda表达式的新特性等这些新特性可以提高开发效率。
3支持最新的技术和框架
许多新的技术和框架已经或即将开始依赖于JDK11或以上版本升级后可以保证应用程序能够分利用这些新的技术和框架。
4长期支持版本
JDK11是Oracle官方发布的一个长期支持LTS意味着它将获得长期的更新和支持有助于保持用程序的稳定性和可靠性。
5行业趋势
数据来自 New Relic 在2023年1月发布的Java生态报告从下图可以看出 1、目前市面上有 超过 56%的应用程序使用了JDK 11Java 8 的使用从2020年的84%降低到了现在的32%左右。大部分公司在这三年之间都升级到了JDK 11 或者 JDK 17这两个LTS版本上面。 2、垃圾收集器使用情况来看JDK11版本及以上 G1使用率最高占比高达65% 3、升级后GC效果 先给出结论 1、JDK11相对于JDK8所有垃圾回收器的性能都有提升特别是大内存机器下G1的提升最明显 2、8G内存以下的机器推荐使用Parallel GC如果特别追求低延迟选择牺牲吞吐量可以使用G1并设置期望的最大垃圾回收停顿时间来控制 3、8G及以上的大内存机器推荐使用G1 4、不推荐使用CMS升级后从各项数据来看CMS收集器都不如G1 我在JDOS平台上选择了不同配置的机器2C4G、4C8G、8C16G并分别使用JDK8和JDK11进行部署和压测。
整个压测过程限时60分钟用180个虚拟用户并发请求一个接口每次接口请求都创建512Kb的数据。最终产出不同GC回收器的各项指标数据来分析GC的性能提升效果。
以下是压测的性能情况 * 上面给出的GC升级效果采用的是默认的配置没有做任何优化只提供参考。真正的GC调优是个技术活需要根据业务需求、机器配置和实际压测效果等综合评估来选出最合适的GC垃圾回收器。
* 不同垃圾回收器的特点
1.Parallel GC - JDK 8及以下版本的默认收集器关注吞吐量尝试在最小延迟的情况下尽快完成工作并提高吞吐量。
2.CMS - 一个老年代收集器基于标记-清除算法实现关注延迟以最短回收停顿时间为目标
3.Garbage FirstG1- JDK 9以后的默认收集器G1 关注总体的性能会尝试在吞吐量和延迟之间做平衡。
4、JDK11带来了哪些新特性
4.1、GC改进 默认垃圾回收器改为G1废弃CMS垃圾回收器 ◦G1特点目标是降低应用程序的停顿时间并提高吞吐量。 引入ZGC垃圾回收器可伸缩低延迟垃圾收集器 但由于JDK11中ZGC还不够完善推荐在JDK17中再使用稳定版ZGC ◦Full GC的停顿不超过10毫秒
◦支持TB级堆内存回收
◦相对于G1吞吐量下降不超过15%
4.2、模块化 Java9引入了对于模块化软件支持而Java11进一步扩展了这种特性。模块化让应用程序 更精简减少对其他类库的依赖和冗余代码提高运行效率和安全性。 然而目前不推荐使用模块化因为相关组件生态还不完善并且模块化带来的价值不够突出。具体原因请看后面章节的详细分析新特性实践-模块化。
4.3、语法增强
◦局部变量推断引入var局部变量类型允许开发人员省略通常不必要的局部变量类型初始化声明 ◦Lambda表达式简化内部可以使用var ◦接口中可以定义私有方法可以实现接口方法的访问控制和代码复用 4.4、API增强
◦**HTTPClient标准化支持**强大而灵活的HTTP客户端API支持多协议HTTP/2、WebSocket、异步非阻塞、流操作和连接池等特性。ps再也不需要用第三包 HttpClient 工具包
◦字符串方法增强isBlank、lines、strip、stripLeading、stripTrailing和repeat
◦Files增强readString、WriteString
◦InputStream增强transferTo流快速拷贝
◦stream增强dropWhile从集合中删除满足的、takeWhile从集合中获取满足的、ofNullable
◦集合工厂方法Sets.of()、List.of()、Map.of()、Map.ofEntries()举例List list List.of(“Java”, “Python”, “C”);
5、如何升级
5.1、升级应用评估
•为保证稳定性我们优先在新业务新应用来落地实施JDK11的升级。
5.2、JDK选择
自从2019年1月起Oracle JDK后续的版本开始商用收费所以推荐大家选择OpenJDK11OpenJDK和OracleJDK功能上没有差异支持免费商用。
OpenJDK11下载地址https://jdk.java.net/archive/
5.3、GC配置 根据自身需求和机器配置选择GC不同GC的JVM启动参数配置 •G1垃圾回收器JDK11默认不需要手动配置-XX:UseG1GC
•Parallel GC垃圾回收器XX:UseParallelGC
5.4、升级过程踩坑 整个升级过程还是比较简单的除了升级JDK版本实际遇到的问题如下 5.5、升级后验证
升级后完成做好单测和回归测试推荐能做个压测验证防止影响线上服务稳定性
6、新特性实践-模块化
Java一直是构建大型应用程序的主流语言之一。然而随着Java生态系统中存在着大量库和复杂的代码块之间关系难以理清的问题构建系统变得困难且超出了我们的理解和有效开发的范围。特别是在使用繁多的Java存档文件Java Archive, JAR时这一问题变得更加突出。为了应对这种复杂性模块化能够很好地管理和减少代码的复杂性。因此自Java9开始引入了模块化系统。通过模块化Java本身也得以进行模块化改进。
6.1、模块化是什么
模块化指的是JAVA平台的模块系统Java Platform Module System简称JPMS。JPMS引入一种新方式来组织和构建Java应用程序它将代码分为相互独立、可复用的模块。每个块都有自己的命名空间明确声明并控制其他模块的访问权限。这种模块化设计使得开发人员能够更好地维护复杂的应用程序提高代码的复用性、可维护性和安全性同时提升应用的加载速度和性能**。最大的特点是可以定义模块描述符来隔离moduleJar包内部类的访问权限。**
模块化的几点关键说明 1相对于JDK8的变动 •JDK9以后引入了一个新组件module模块描述符module-info.java用于将一组相关的包放入一个组中。
•在Java8和更早的应用程序中应用程序将包作为顶级组件Java9以后应用程序将模块作为顶级组件
•一个模块Jar包只能有一个module-info.java。 2和maven的关系 模块化并不是要替代maven和maven本身并不冲突maven定义jar之间的依赖关系模块化是对已经依赖的jar下的包进行更细粒度依赖控制 3如何兼容旧应用 天然兼容旧应用。为了向后兼容旧项目一些库本身并未模块化其仍然可以作为模块在模块路径中使用而这些库在模块路径上时会被转化为自动模块例如jackson-databind-1.0.0.jar将成为自动模块jackson.databind 6.2、带来了哪些好处
1封装和隔离更好的访问控制
模块化允许开发者将代码和资源封装在独立的模块中。模块之间可以明确地定义公开和私有的API提供了更好的代码隔离性和可维护性。
ps新业务单应用可以按照领域模型来进行多模块的划分以避免代码腐化。简单举例单应用下存在产品.jar、订单.jar。订单依赖产品通过模块化的限制订单只能使用产品中明确对外暴露的类这样就避免传统模式订单.jar可能依赖了产品.jar中普通的类导致代码腐化的问题也降低后续领域服务拆分的复杂度
2更好的可伸缩性加载速度的提升
模块化系统使得Java平台更加可伸缩通过模块化定义可以仅加载需要的模块从而提升加载类的效率最终减少了应用程序的内存占用和启动时间同时打包后的程序也更小。
3明确的依赖关系
模块化系统要求在模块之间明确定义依赖关系。在编译或运行代码之前模块系统会检查模块是否满足所有依赖关系从而导致更少的运行时错误。
4安全
在JVM的最深层次上执行强封装减少Java运行时的攻击面同时无法获得对敏感内部类的反射访问。
6.3、如何使用
1定义module-a.jar
包结构如下
com.jdt.a person Men.java reflect ReflectModel.java module-info.java module-info文件内容如下
module module.a { //指令用于指定一个模块中哪些包下的public对外是可访问的包括直接引入和反射使用 exports com.jdt.a.person; // 只能被反射调用用于指定某个包下所有的 public 类都只能在运行时可被别的模块进行反射并且该包下的所有的类及其乘员都可以通过反射进行访问。 opens com.jdt.a.refect; }2定义module-b.jar,包的pom中指定依赖了module-a
包结构如下
com.jdt.b test Test.java module-info.java module-info文件内容如下
module module.b { //依赖a下的包 requires module.a;}3此时module-b.jar,在编写编码时会遇到如下问题 6.4、实践过程的坑
上面简单介绍了模块化的知识具体在落地过程中我们主要踩了以下的坑供大家参考
1依赖JSF包时无法模块化
* JSF是京东内部使用的高性能RPC框架
进行模块化时pom中依赖了jsf包模块定义如下
module module.a { requires fastjson; //依赖jsf包名 requires jsf.lite; exports com.jd.jdk.test.module;}此时编译报错如下提示找不到模块jsf.lite但是pom中明明指定依赖了jsf.lite 问题原因
经过一系列定位研究发现jsf-lite包中/META-INF/services下的文件org.glassfish.jersey.internal.spi.AutoDiscoverable里面写的类是com.alibaba.fastjson.support.jaxrs.FastJsonAutoDiscoverable此类并未在当前jsf.lite包中定义属于com.alibaba.fastjson包的。 但是我们的pom中明明也依赖了com.alibaba.fastjson包为什么模块化后就找不到了呢
主要原因在于模块化遇到SPIService Provider Interface时的约束模块化时SPI机制要求配置中定义依赖的类必须本模块定义的不能是其他模块的包来自它不拥有的包否则此包将无法被模块化
这样也就解释了为什么上面jsf无法找到module的问题jsf-lite里面设置了它不拥有的包com.alibaba.fastjson.support.jaxrs.FastJsonAutoDiscoverable导致jsf-lite包无法被自动模块化
解决方案
1、联系JSF团队升级JSF包修复上面说的FastJsonAutoDiscoverable配置错误的问题。
2拆包问题模块隔离
模块化约束jdk9以上使用模块化时不支持拆分包的形式依赖
拆分包意味着两个模块包含相同的包Java模块系统不允许拆分包。拆分包始终是不正常的而当使用解析可传递依赖项的构建工具如Maven等时很容易出现同一个库的多个版本当Java模块系统检测到一个包存在于模块路径上的多个模块中时就会拒绝启动。
例如
module-a.jar包结构定义com.foo.package A.java module-b.jar包结构定义com.foo.package B.java 当module-c同时依赖module-a和module-b时如上编译时会报一个错Package com.foo.package in both module module.b and module module.a这就是JAVA9的模块隔离要求只能从一个模块module中读取同一个包package不能跨模块读取。
解决方案
如果在使用模块化时遇到了拆分包问题无论如何都是无法绕过的。即使从用户角度来看基于类路径的应用程序可以正确工作你也最终需要处理这些问题。此时只能停用模块化或升级jar包避免拆分包问题
6.5、模块化落地总结
目前不推荐使用模块化因为相关组件生态还不完善并且模块化带来的价值不够突出
1.很多中间件都是基于jdk8构建的都有可能遇到模块化兼容的问题比如jsf需要jsf强制升级才可以使用模块化
2.拆包问题无法解决比如aws-java-sdk-s3、fluent等。
7、总结 1、升级过程简单升级后可以使用更多新特性和更好的GC性能所以 建议升级到JDK11。 2、现阶段 不推荐使用模块化但是不用担心会影响JDK11的升级。 另外听说JDK17的 ZGC可以达到亚秒级停顿但考虑到JDK11的ZGC还不是很稳定所以本次不做测试后面升级到JDK17后再给大家分享ZGC压测效果。
希望以上分享可以给大家带来实际的帮助。
本文转自 https://baijiahao.baidu.com/s?id1777604192158753657wfrspiderforpc