背景
亞馬遜通生態客戶要求使用jdk17,而目前idaas的架構使用的是openjdk11版本,需要調研jdk17的特點以及與jdk11的不同點,是否能無感升級?
標黃的部分可以重點關注下
306: Restore Always-Strict Floating-Point Semantics
356: Enhanced Pseudo-Random Number Generators
為偽隨機數生成器(PRNG)提供新的接口類型和實現,包括可跳轉PRNG和一類額外的可拆分PRNG算法(LXM)。
382: New macOS Rendering Pipeline
使用Apple Metal API為macOS實現Java 2D內部渲染管道,作為現有管道的替代,現有管道使用已棄用的Apple OpenGL API。
391: macOS/AArch64 Port 可忽略
398: Deprecate the Applet API for Removal
概述:棄用Applet API進行刪除。這基本上是無關緊要的,因為所有的web瀏覽器供應商要么已經取消了對Java瀏覽器插件的支持,要么宣布了這樣做的計劃。
403: Strongly Encapsulate JDK Internals
強烈封裝JDK的所有內部元素,但關鍵的內部API(如sun.misc.Unsafe)除外。不再可能像JDK 9到JDK 16中那樣,通過單個命令行選項放松內部元素的強大封裝。
406: Pattern Matching for switch (Preview)
switch case的代碼塊增加了表達式和類型支持,對我們編碼整潔度和效率有了提升。
407: Remove RMI Activation
刪除遠程方法調用(RMI)激活機制,同時保留RMI的其余部分。
409: Sealed Classes
密封類或接口只能由允許這樣做的類和接口擴展或實現。通過對類的聲明應用密封修飾符來密封類
410: Remove the Experimental AOT and JIT Compiler
刪除實驗性的基于Java的提前(AOT)和實時(JIT)編譯器。這個編譯器自推出以來幾乎沒有什么用處,維護它所需的努力也很重要。保留實驗性的Java級JVM編譯器接口(JVMCI),以便開發人員可以繼續使用編譯器的外部構建版本進行JIT編譯
411: Deprecate the Security Manager for Removal
不推薦Security Manager,以便在將來的版本中刪除。安全管理器可以追溯到Java 1.0。多年來,它一直不是保護客戶端Java代碼的主要手段,也很少用于保護服務器端代碼。為了使Java向前發展,我們打算不推薦安全管理器與遺留的Applet API(JEP 398)一起刪除。
412: Foreign Function & Memory API (Incubator)
FFM豐富了外部函數和堆外內存的api,提升了jvm和跨平臺能力
414: Vector API (Second Incubator)
引入一個API來表達向量計算,在運行時可靠地編譯為支持的CPU架構上的最優向量指令,從而實現優于等效標量計算的性能。
415: Context-Specific Deserialization Filters
382:(增強型功能)
概述:
使用Apple Metal API為macOS實現Java 2D內部渲染管道,作為現有管道的替代,現有管道使用已棄用的Apple OpenGL API。
目標:
1、為使用macOS Metal框架的Java 2D API提供功能齊全的渲染管道。
2、如果蘋果從未來版本的macOS中刪除了不推薦使用的OpenGL API,請做好準備。
3、確保Java應用程序的新管道的透明度。
4、確保實現與現有OpenGL管道的功能對等。
5、在選定的實際應用程序和基準測試中,提供與OpenGL管道相同或更好的性能。
6、創建適合現有Java2D管道模型的干凈架構。
7、與OpenGL管道共存,直到其過時
356:(增強型功能)
概述:
為偽隨機數生成器(PRNG)提供新的接口類型和實現,包括可跳轉PRNG和一類額外的可拆分PRNG算法(LXM)。
改造細節:
我們提供四個新的專用RandomGenerator接口:
1、SplitableRandomGenerator擴展了RandomGeneration,還提供
名為split和splits的方法。可拆分性允許用戶從現有的RandomGenerator中生成一個新的Random生成器,
該生成器通常會產生統計上獨立的結果。
2、JumpableRandomGenerator擴展了RandomGeneration,還提供
方法名為jump和jumps。可跳躍性允許用戶向前跳躍適度的平局次數。
3、LeapableRandomGenerator擴展了RandomGeneration,還提供
命名為leap和leaps的方法。可跳躍性允許用戶在大量抽簽前跳躍。
4、ArbitrilyJumpableRandomGenerator擴展了LeapableRandomGeneration,還提供了跳躍和跳躍的其他變體,允許指定任意跳躍距離。
398:(刪除或回收功能)
概述:棄用Applet API進行刪除。這基本上是無關緊要的,因為所有的web瀏覽器供應商要么已經取消了對Java瀏覽器插件的支持,要么宣布了這樣做的計劃。Java 9中的JEP 289以前不推薦使用Applet API,但不允許刪除。
改造細節:
風險和假設
如果這些API仍然存在,開發人員可以通過@SuppressWarnings(“remove”)注釋或javac編譯器的-Xlint:-remove命令行選項來抑制編譯器警告。
403:(增強型功能)
概述:
強烈封裝JDK的所有內部元素,但關鍵的內部API(如sun.misc.Unsafe)除外。不再可能像JDK 9到JDK 16中那樣,通過單個命令行選項放松內部元素的強大封裝。
目標:
1、繼續提高JDK的安全性和可維護性,這是Project Jigsaw的主要目標之一。
2、鼓勵開發人員從使用內部元素遷移到使用標準API,這樣他們和他們的用戶都可以輕松升級到未來的Java版本。
改造原因:
多年來,各種庫、框架、工具和應用程序的開發人員使用JDK的內部元素的方式損害了安全性和可維護性。特別地:
java.*包的一些非公共類、方法和字段定義了特權操作,如在特定類加載器中定義新類的能力,而其他類則傳遞敏感數據,如加密密鑰。盡管這些元素位于java.*包中,但它們都是JDK的內部元素。外部代碼通過反射使用這些內部元素會使平臺的安全面臨風險。
sun.*包的所有類、方法和字段都是JDK的內部API。com.sun.*、jdk.*和org.*包的大多數類、方法和字段也是內部API。這些API從來都不是標準的,從來都不受支持,也從來沒有打算供外部使用。外部代碼使用這些內部元素是持續的維護負擔。為避免破壞現有代碼而保存這些API所花費的時間和精力,最好是將平臺向前移動。
改造細節:
1、在Java9中,我們利用模塊來限制對JDK內部元素的訪問,從而提高了JDK的安全性和可維護性。模塊提供強大的封裝,這意味著模塊外部的代碼只能訪問該模塊導出的包的公共和受保護元素,并且
此外,受保護的元素只能從定義它們的類的子類中訪問。
2、強封裝適用于編譯時和運行時,包括編譯代碼試圖在運行時通過反射訪問元素時。導出包的非公共元素和未導出包的所有元素都被稱為強封裝。
3、在JDK9和更高版本中,我們強烈封裝了所有新的內部元素,從而限制了對它們的訪問。然而,為了幫助遷移,我們故意選擇在運行時不強封裝JDK8中存在的內部元素。因此,類路徑上的庫和應用程序代碼可以繼續使用反射來訪問java的非公共元素。*包裝和太陽的所有元素。*對于JDK8中存在的包,這種安排被稱為輕松強封裝,是JDK9中的默認行為。
4、我們早在2017年9月就發布了JDK 9。JDK的大多數常用內部元素現在都有標準替換。開發人員有三年多的時間從JDK的內部元素遷移到標準API,如java.lang.invoke.MethodHandles。查找::defineClass,java.util。Base64和java.lang.ref.Cleaner。許多庫、框架和工具維護人員已經完成了遷移,并發布了其組件的更新版本。與2017年相比,現在對寬松的強封裝的需求減弱了,而且每年都會進一步減弱。
5、在2021發布的JDK 16中,我們朝著強大封裝JDK的所有內部元素邁出了下一步。JEP 396對默認行為進行了強封裝,但關鍵的內部API(如sun.misc)除外。不安全,仍然可用。在JDK16中,最終用戶仍然可以選擇寬松的強封裝,以便訪問JDK8中存在的內部元素。
6、我們現在準備在這一旅程中再邁出一步,取消選擇輕松強封裝的能力。這意味著JDK的所有內部元素都將被強封裝,除了sun.misc.Unsafe等關鍵的內部API。
406:(增強型功能)
概述:
通過switch表達式和語句的模式匹配以及對模式語言的擴展來增強Java編程語言。將模式匹配擴展到switch允許根據多種模式對表達式進行測試,每種模式都有一個特定的操作,從而可以簡潔而安全地表達復雜的面向數據的查詢。這是JDK 17中的預覽語言功能。
目標:
1、通過允許模式出現在case標簽中,擴展switch表達式和語句的表達能力和適用性。
2、允許在需要時放松開關的歷史零敵意。
3、引入兩種新的模式:保護模式(允許使用任意布爾表達式來細化模式匹配邏輯)和圓括號模式(解決一些解析歧義)。
4、確保所有現有的switch表達式和語句繼續編譯而不發生任何更改,并以相同的語義執行。
5、不要引入與傳統switch結構不同的具有模式匹配語義的新的類switch表達式或語句。
6、當大小寫標簽是模式時,不要使switch表達式或語句的行為與大小寫標簽為傳統常量時不同。
改造細節:
在Java 16中,JEP 394擴展了instanceof運算符,以獲取類型模式并執行模式匹配。這個適度的擴展允許簡化熟悉的instanceof和cast習慣用法:
// Old code
if (o instanceof String) {
String s = (String)o;
... use s ...
}
// New code
if (o instanceof String s) {
... use s ...
}
Old code:
static String formatter(Object o) {
String formatted = "unknown";
if (o instanceof Integer i) {
formatted = String.format("int %d", i);
} else if (o instanceof Long l) {
formatted = String.format("long %d", l);
} else if (o instanceof Double d) {
formatted = String.format("double %f", d);
} else if (o instanceof String s) {
formatted = String.format("String %s", s);
}
return formatted;
}
New code:
static String formatterPatternSwitch(Object o) {
return switch (o) {
case Integer i -> String.format("int %d", i);
case Long l -> String.format("long %d", l);
case Double d -> String.format("double %f", d);
case String s -> String.format("String %s", s);
default -> o.toString();
};
}
傳統上,如果選擇器表達式的計算結果為null,switch語句和表達式會拋出NullPointerException,因此必須在switch之外進行null測試:
Old code:
static void testFooBar(String s) {
if (s == null) {//會多加這一句非空判斷
System.out.println("oops!");
return;
}
switch (s) {
case "Foo", "Bar" -> System.out.println("Great");
default -> System.out.println("Ok");
}
}
當交換機只支持少數引用類型時,這是合理的。然而,如果switch允許任何類型的選擇器表達式,并且case標簽可以有類型模式,那么獨立的null測試感覺就像是一種任意的區分,并且會帶來不必要的樣板和出錯的機會。最好將空測試集成到交換機中:
New code:
static void testFooBar(String s) {
switch (s) {
case null -> System.out.println("Oops");
case "Foo", "Bar" -> System.out.println("Great");
default -> System.out.println("Ok");
}
}
既然支持了null這種類型,那么對象類型應該也可以
class Shape {}
class Rectangle extends Shape {}
class Triangle extends Shape { int calculateArea() { ... } }
static void testTriangle(Shape s) {
switch (s) {
case null:
break;
case Triangle t:
if (t.calculateArea() > 100) {
System.out.println("Large triangle");
break;
}
default:
System.out.println("A shape, possibly a small triangle");
}
}
還可以進一步簡化:
static void testTriangle(Shape s) {
switch (s) {
case Triangle t && (t.calculateArea() > 100) ->
System.out.println("Large triangle");
default ->
System.out.println("A shape, possibly a small triangle");
}
}
寫到這里大家肯定會問,現在可以支持Enum枚舉類型了吧,回答當然可以。
record Point(int i, int j) {}
enum Color { RED, GREEN, BLUE; }
static void typeTester(Object o) {
switch (o) {
case null -> System.out.println("null");
case String s -> System.out.println("String");
case Color c -> System.out.println("Color with " + Color.values().length + " values");
case Point p -> System.out.println("Record class: " + p.toString());
case int[] ia -> System.out.println("Array of ints of length" + ia.length);
default -> System.out.println("Something else");
}
}
407:(刪除或回收功能)
概述:刪除遠程方法調用(RMI)激活機制,同時保留RMI的其余部分。
刪除原因:
RMI激活機制已過時并被廢棄。Java SE 15中的JEP 385不贊成刪除它。沒有收到對該不贊成的評論。請參見JEP 385了解完整的背景、原理、風險和備選方案。
JavaEE平臺包含一種稱為JavaBeans激活框架(JAF)的技術。作為Eclipse EE4J計劃的一部分,該項目后來被更名為雅加達激活。JavaBeans Activation和Jakarta Activation技術與RMI Activation完全無關,它們不受從Java SE中刪除RMI Activition的影響。
改造細節:
刪除java.rmi。Java SE API規范中的激活包
更新RMI規范,刪除RMI激活
刪除實現RMI激活機制的JDK庫代碼
刪除RMI激活機制的JDK回歸測試
刪除JDK的rmid激活守護程序及其文檔
風險和假設
對于JEP 385對RMI激活的否決,沒有收到任何評論。然而,這并不構成對RMI活化沒有依賴性的證據。移除RMI激活后,仍有可能破壞某些現有系統。反過來,這種系統的存在并不一定是保持RMI激活的有力理由。相反,移除RMI激活有助于強調需要為該系統制定更好的緩解計劃。該計劃不需要是緊急情況;使用RMI激活的現有系統將在具有長期或擴展支持的舊JDK版本上繼續運行一段時間。
409:(增強型功能)
概述:**sealed****(密封) 和 permits(許可)修飾符
密封類或接口只能由允許這樣做的類和接口擴展或實現。通過對類的聲明應用密封修飾符來密封類。然后,在任何擴展和實現子句之后,permits子句指定允許擴展密封類的類。例如,下面的Shape聲明指定了三個允許的子類:
package com.example.geometry;
public abstract sealed class Shape
permits Circle, Rectangle, Square { ... }
使用密封的類和接口增強Java編程語言。密封類和接口限制了哪些其他類或接口可以擴展或實現它們。
歷史:
密封類由JEP 360提出,并在JDK 15中作為預覽功能提供。它們由JEP 397再次提出并進行了改進,并作為預覽功能在JDK 16中提供。本JEP建議在JDK17中最終確定密封類,而不改變JDK16。
目標:
1、允許類或接口的作者控制負責實現它的代碼。
2、提供一種比訪問修飾符更具聲明性的方式來限制超類的使用。
3、通過為模式的詳盡分析提供基礎,支持模式匹配的未來方向。
410:(刪除或回收功能)
概述:
刪除實驗性的基于Java的提前(AOT)和實時(JIT)編譯器。這個編譯器自推出以來幾乎沒有什么用處,維護它所需的努力也很重要。保留實驗性的Java級JVM編譯器接口(JVMCI),以便開發人員可以繼續使用編譯器的外部構建版本進行JIT編譯。
刪除原因:
提前編譯(jaotc工具)通過JEP 295作為一個實驗特性被納入JDK 9。jaotc使用Graal編譯器進行AOT編譯,Graal編譯器本身是用Java編寫的。
Graal編譯器通過JEP 317作為JDK 10中的實驗JIT編譯器提供。
自從這些實驗特性被引入以來,我們幾乎沒有看到它們的使用,維護和增強它們所需的努力非常重要。Oracle發布的JDK16版本中沒有包含這些功能,沒有人抱怨。
改造細節:
卸下三個JDK模塊:
jdk.aot-jaotc工具
jdk.internal.vm.compiler-Graal編譯器
jdk.internal.vm.compiler.management-Graal的MBean
保留這兩個與Graal相關的源文件,以便JVMCI模塊(jdk.internal.vm.ci,JEP 243)繼續構建:
src/jdk.internal.vm.compiler/share/classes/module-info.java
src/jdk.internal.vm.compiler.management/share/classes/module-info.java
刪除與AOT編譯相關的熱點代碼:
src/hots/share/aot-轉儲和加載aot代碼
由#if INCLUDE_AOT保護的附加代碼
最后,刪除與Graal和AOT編譯相關的測試以及生成文件中的代碼
411:(刪除或回收功能)
概述:
不推薦Security Manager,以便在將來的版本中刪除。安全管理器可以追溯到Java 1.0。多年來,它一直不是保護客戶端Java代碼的主要手段,也很少用于保護服務器端代碼。為了使Java向前發展,我們打算不推薦安全管理器與遺留的Applet API(JEP 398)一起刪除。
目標:
為開發人員在未來版本的Java中刪除Security Manager做好準備。
警告用戶其Java應用程序是否依賴Security Manager。
評估是否需要新的API或機制來解決安全管理器所使用的特定狹窄用例,例如阻塞System::exit。
動機:
Java平臺強調安全性。數據的完整性受到Java語言和VM內置內存安全的保護:變量在使用前被初始化,數組邊界被檢查,內存釋放是完全自動的。同時,數據的機密性受到Java類庫對現代加密算法和協議(如SHA-3、EdDSA和TLS 1.3)的可信實現的保護。安全是一門動態科學,因此我們不斷更新Java平臺,以解決新的漏洞并反映新的行業姿態,例如通過貶低弱加密協議。
隨著對Java興趣的增長,我們引入了簽名小程序,以允許安全管理器信任遠程代碼,從而允許小程序訪問與通過命令行上的Java運行的本地代碼相同的資源。與此同時,Java類庫正在迅速擴展——Java 1.1引入了JavaBeans、JDBC、Reflection、RMI和Serialization——這意味著可信代碼可以訪問重要的新資源,如數據庫連接、RMI服務器和反射對象。允許所有受信任的代碼訪問所有資源是不可取的,因此在Java 1.2中,我們重新設計了安全管理器,將重點放在應用最小權限原則上:默認情況下,所有代碼都將被視為不受信任的,受沙盒式控制的影響,并且用戶將通過授予他們訪問特定資源的特定權限來信任特定的代碼庫。理論上,類路徑上的應用程序JAR在如何使用JDK方面可能比來自Internet的小程序更受限制。限制權限被視為一種限制代碼體中可能存在的任何漏洞影響的方法——實際上,這是一種深度防御機制。
當時,安全管理器有雄心壯志,要防范兩種威脅:惡意意圖(尤其是遠程代碼)和意外漏洞(尤其是本地代碼)。
由于Java平臺不再支持小程序,遠程代碼的惡意威脅已經減弱。2017年,小程序API在Java 9中被棄用,然后在2021被棄用以在Java 17中刪除,目的是在未來的版本中刪除它。2018年,運行小程序的封閉源代碼瀏覽器插件與封閉源代碼Java Web Start技術一起從Oracle的JDK 11中刪除。因此,Security Manager所保護的許多風險不再重要。此外,Security Manager無法防范現在非常重要的許多風險。安全管理器無法解決行業領導者在2020年發現的25個最危險的問題中的19個,因此XML外部實體引用(XXE)注入和不正確的輸入驗證等問題需要Java類庫中的直接對策。(例如,JAXP可以防止XXE攻擊和XML實體擴展,而序列化過濾可以防止惡意數據在造成任何損害之前被反序列化。)安全管理器也無法防止基于推測執行漏洞的惡意行為。
總之,對使用SecurityManager開發現代Java應用程序沒有太大興趣。基于權限做出訪問控制決策既笨拙又緩慢,而且在整個行業中都不受歡迎。NET不再支持它。通過在Java平臺的較低級別提供完整性(例如,通過加強模塊邊界(JEP 403)以防止訪問JDK實現細節,并強化實現本身),以及通過進程外機制(如容器和管理程序)將整個Java運行時與敏感資源隔離,可以更好地實現安全性。為了推動Java平臺的發展,我們將不贊成從JDK中刪除傳統的Security Manager技術。我們計劃在多個版本中棄用和削弱SecurityManager的功能,同時為諸如阻止System::exit和其他被認為足夠重要的用例等任務創建替代API
備注:In Java 17, we will
棄用大多數與Security Manager相關的類和方法以進行刪除。
如果在命令行上啟用了安全管理器,則在啟動時發出警告消息。
如果Java應用程序或庫動態安裝Security Manager,則在運行時發出警告消息。
改造細節:
java.lang.SecurityManager
java.lang.System::{setSecurityManager, getSecurityManager}
java.security.{Policy, PolicySpi, Policy.Parameters}
java.security.{AccessController, AccessControlContext, AccessControlException, DomainCombiner}
412:(增強型功能)
概述:
介紹一個API,通過該API,Java程序可以與Java運行時之外的代碼和數據進行互操作。通過有效地調用外部函數(即JVM外部的代碼),并通過安全地訪問外部內存(即不由JVM管理的內存),API使Java程序能夠調用本地庫并處理本地數據,而不會出現JNI的脆弱性和危險性。
Java平臺一直為希望超越JVM并與其他平臺交互的庫和應用程序開發人員提供了豐富的基礎。Java API以方便可靠的方式公開非Java資源,無論是訪問遠程數據(JDBC)、調用web服務(HTTP客戶端)、服務遠程客戶端(NIO通道)還是與本地進程(Unix域套接字)通信。不幸的是,Java開發人員在訪問一種重要的非Java資源時仍然面臨著巨大的障礙:代碼和數據與JVM在同一臺機器上,但在Java運行時之外。
目標:
易用性-用一個優秀的純Java開發模型取代Java本機接口(JNI)。
性能—提供與現有API(如JNI和sun.misc.Unsafe)相當的性能(如果不是更好的話)。
通用性-提供在不同類型的外部內存(例如,本機內存、持久內存和托管堆內存)上操作的方法,并隨著時間的推移,適應其他平臺(例如,32位x86)和用C以外的語言編寫的外部函數(例如,C++、Fortran)。
安全-默認情況下禁用不安全操作,僅在應用程序開發人員或最終用戶明確選擇后才允許它們
改造細節:
ByteBufferAPI允許創建堆外分配的直接字節緩沖區,但它們的最大大小為2GB,不會立即釋放。這些和其他限制源于這樣一個事實,即ByteBuffer API不僅設計用于堆外內存訪問,還設計用于字符集編碼/解碼和部分I/O操作等領域的批量數據的生產者/消費者交換。
414:(增強型功能)
概述:
引入一個API來表達向量計算,在運行時可靠地編譯為支持的CPU架構上的最優向量指令,從而實現優于等效標量計算的性能。
對API的增強,以支持對字符的操作,例如UTF-8字符解碼。具體來說,我們添加了用于在短向量和字符數組之間復制字符的方法,以及用于與整數向量進行無符號比較的新向量比較運算符。
API的增強功能,用于在布爾數組之間轉換字節向量。
使用英特爾的短矢量數學庫(SVML),對x64上的超越和三角車道運算提供內在支持。
Intel x64和ARM NEON實現的一般性能增強。
415:(增強型功能)
概述:
允許應用程序通過JVM范圍的過濾器工廠配置上下文特定的和動態選擇的反序列化過濾器,該過濾器工廠用于為每個反序列化操作選擇過濾器