回首Java——再回首JDK

JoruaChan 發表於 2020-08-01

如果你是剛要被Java軍訓的新兵,可有幾時對環境搭建而不知所措?又如若你是馳騁Java戰場多年的老將,可曾拿起陪伴你許久的82年的JDK回味一番?今天我們就來道一道JDK,重新來認識認識這個既熟悉又陌生的夥伴。

既然要嘮嘮JDK,首先想到的,肯定是要了解下都是誰來推進Java和JDK發展的。

Java發展的會議與組織

說起Java的起源必定要提起Sun公司,由其發起了專屬於Java的JavaOne會議。不過Sun公司被Oracle收購後,JavaOne會議同Oracle先前的Oracle OpenWorld會議併成了Oracle Code One會議,並且會議內容也不再單純討論Java的發展。另外還有JCP(Java Community Process)是個開放性的國際技術標準組織,職責是發展和更新Java 技術規範,由其推出了大量Java相關技術規範JSR,具體可點此檢視。JCP的運作方式是由個人或者廠商提出JSR規範提案,再有JCP委員會的成員投票表決是否採用。其弊端是JCP委員會還是主要由廠商組成,這些規範可能更偏向於廠商的利益,而非大眾的利益。

JDK版本

我們要知道Java應用開發並不是只有常接觸的移動端 、服務端的應用開發。Sun公司根據不同業務領域方向分成了四個JDK版本:

  • Java Card,主要是以具有安全防護性的方式來執行小型的Java Applet,廣泛運用在SIM卡、提款卡上;
  • Java SE,前稱J2SE。Java的標準版,為JavaEE和JavaME提供了基礎類庫以及能力。也是我們安裝部署Java環境最基礎的版本;
  • Java EE,前稱J2EE。針對企業級應用的加強版。主要涉及的技術:JDBC、EJB(被Spring遮住了光芒)、Servlet、RMI、JNDI、JMS、JPA、JTS等。Java 10版本以後被Oracle公司放棄,捐獻給了Eclipse基金會,並後成為Jakarta EE;
  • Java ME,前稱J2ME。主要用於移動裝置、嵌入式裝置上的java應用程式;

Oracle JDK vs Open JDK

至於它倆的區別,下面的列表基本列出:

  Oracle JDK Open JDK
起源時間 JDK1.0,1996年1月發行 OpenJDK 6(基於Java SE 7),2007年發行
程式碼協議

新的OTN協議,2019年1月之後釋出的Oracle JDK 8更新將無法用於商業

GPLv2+CE
發行週期

JDK6及之前大約每兩年一版本,6至7五年,7至8、8至9三年;JDK10及以後均6個月一個大版本;每3年一個LTS版本;

OpenJDK 9及之前大約三年一個版本;OpenJDK 10及以後均6個月一個大版本;

支援時間

從JDK10起,每6個月一個大版本;從JDK11起,每3年一個LTS長期維護的版本;

從JDK10起,每6個月一個大版本;不發行LTS版本,只維護半年,也就是下個版本釋出便不再維護。但是有其他頂級公司繼續維護,如Red Hat OpenJDK,Liberica OpenJDK

商標 java商標擁有者 不可使用java
效能 響應能力、JVM效能更強 ——
功能

Flight Recorder,Java Mission Control和Application Class-Data Sharing

Font Renderer,但OpenJDK 11後也包含Oracle JDK的功能,還有Z Garbage Collector


如果你們公司既想應用新特性,又沒有授權的話,那就使用OpenJDK 11吧!畢竟Oracle的產品總監也說了,Oracle JDK是基於OpenJDK原始碼構建的,OracleJDK和OpenJDK在Java 11後,功能基本保持一致。可見連結:Oracle JDK Releases for Java 11 and Later

各版本特性及重要事件

JDK 1.0在1996年1月23日釋出,Java語言有了第一個正式版本的執行環境;

JDK 1.2,Sun公司正式將Java拆分成J2SE,J2EE和J2ME三大技術體系;

JDK 1.6,終結了J2EE、J2SE、J2ME的命名方式,啟用Java SE 6、JavaEE 6、Java ME 6的命名方式。與此同時,Sun公司宣佈將對Java技術開源;

JDK 7,Sun公司被Oracle公司收購,釋出時間延期;

JDK 8,Oracle啟用JEP(JDK Enhancement  Proposal)定義管理新版JDK釋出的新特性,完成了JDK 7規劃了但沒有實現的功能,HotSpot移除掉永久代,吸收了JRockit的Java Mission Control監控工具等功能;8u201/202版本後,如果是用作商業用途,需要收費;

JDK 9,jigsaw模組化、增強jshell、jlink、jhsdb等工具,並支援了91個JEP;此前均以特性驅動發行版本。9開始變成以時間驅動,釋出週期為6個月一個大版本,3年一個 LTS版本;

JDK 10,主要是JDK內部重構,只支援了12個JEP;Oracle公司拋棄Java EE,捐獻給Eclipse基金會;

JDK 11,推出了ZGC垃圾收集器(只支援64位的Linux機器),支援了17個JEP;第一個官宣的LTS發行版;

JDK 12:推出非Oracle開發的Shen-andoah垃圾收集器,OracleJDK隨後剔除了,存在於OpenJDK,支援了8個JEP;

JDK 13:支援5個JEP;

JDK 14:推出Windows和MacOS的ZGC垃圾收集器,支援16個JEP;

各版本具體的New Feature,大家可以直接上Oracle官網追溯。或者檢視我推薦的兩篇博文:博文1傳送門博文2傳送門。我這裡就不再贅述了,後面會開個專欄,去探索實踐Java每個版本特性的實現。

精華!!!解密JDK包

JDK的運用,滲透到從事Java開發工作的各位的每一天,從開發到除錯,再到釋出和部署,以及上線後的運維都息息相關。相信在座的各位,一定有過疑問,jdk到底是怎麼組成的?瞭解這些可能對我們的開發工作沒有太多的作用,但是哪位又能預料明天和bug哪個先到呢,也許這就是你找到問題根因的地方!再不濟,學習點知識,總不會有壞處!跟隨我的腳步,一起看看JDK到底是怎麼構成的吧!

組成架構

我們先來看下官方文件中Java SE版本JDK的組成架構圖:

回首Java——再回首JDK

很直接地可以看出,最下面的Java HotSpot VM,是Java執行最基礎的元件;Java SE API即我們日常程式設計使用的Java類庫;JRE是Java應用程式執行的最小環境,其中包括了JVM,Java SE API類庫和其他標準或非標準元件;JDK包含了JRE和一些Tool。Java8增加新特性Compact Profiles,是因為Java豐富的類庫在小型應用中顯得有些累贅,便將JRE分成了三種實現,compact1、compact2和compact3,具體的拆分情況如下,可見數字越大,包含的內容越多。在編譯時,使用option: -profile,指定對應的實現方式即可。

回首Java——再回首JDK

JDK檔案組成

以windows環境的Java 8u261版本為例,針對JDK的組成架構進行解讀。先來了解下解壓或者安裝完JDK的資料夾結構吧:

回首Java——再回首JDK

  • bin目錄中存放了開發過程的編譯解釋工具,如java.exe、javac.exe等,以及開發運維工作中常用的資源消耗統計等不同功能的輔助工具,如jmap.exe、jconsole.exe、jstat.exe等。
  • include目錄下可以看到都是以.h結尾的檔案,用來支援Java中用到的本地方法以及JVM除錯程式介面用到的本地技術。
  • jre目錄則是jdk執行的開發環境時使用的runtime,如jdk bin目錄下的執行檔案都是建立在這個jre資料夾的基礎上 !當然也是可以單純用於Java編寫的程式。需要說明的,如果存在期望依賴的jar包(如中介軟體的驅動程式),可以放置於jre的lib目錄下的ext資料夾 。
  • lib目錄是存放JDK bin目錄下可執行檔案依賴的jar包等,如常見的tools.jar;
  • src.zip則是Java類庫原始碼,主要包含rt.jar,以及程式啟動器Launcher原始碼,主要功能是建立ExtClassLoader和AppClassLoader,根據配置建立SercurityManager,設定程式上下文類載入器;

JVM

Oracle官網po出組成架構圖最下面便是最基礎、最重要的JVM技術,是在真實計算機上模擬虛擬的計算機功能。正是它的存在,才成就了“一次編譯,多次執行”;

Java8後提供了兩種模式的VM,一種是Client,通常用於客戶端應用程式,可以減少應用的啟動時間和記憶體佔用,一種是Server,會提升執行時執行速度;在jvm.cfg檔案中第一個是預設實現,預設是-server KNOWN,KNOWN可設定成IGNORE,這只是表示相應的option是否啟用。

此處列出兩個Q&A,這也是我最初接觸JVM的疑問。

Q1:JVM作為Java程式最重要的元件,為什麼資料夾裡沒有一個很明顯的檔案表示用於JVM的呢?

A1:JVM以動態庫的形式存在,Windows上置於jre的bin資料夾下的server或者client資料夾裡的jvm.dll。Linux上置於jre的lib檔案下的/amd**/server或者/amd**/client資料夾下的libjvm.so。

Q2:JVM是怎麼被載入並例項化的?

A2:JVM載入是通過java.exe來完成:首先通過launcher下的main函式建立JVM裝載環境、配置,然後裝載jvm.dll,裝載完成後通過JNI本地呼叫介面找到JNI_CreateJavaVM的函式地址,然後呼叫函式去例項化JNIEnv物件:JVM,最後便通過JVM例項裝載並處理class檔案。程式碼呼叫順序如下,童鞋可自行看下原始碼:main() > JLI_Launch() > CreateExecutionEnvironment() > SetJvmEnvironment() > LoadJavaVM() > JVMInit() > JavaMain() > InitializeJVM() > CreateJavaVM() [呼叫JNI介面] > LoadMainClass() > GetApplicationClass() ;

哦~~原來是這樣啊!是不是對JVM進一步認識了呢?不過這才是皮毛,剩下的等我開個專題慢慢道來!還不趕緊關注我?

 JRE 依賴包

JRE執行所依賴的jar包,包含在/jre/lib和/jre/lib/ext資料夾下,如果有jar包希望作為JVM信任的Jar包第一時間載入,也可以直接將jar包置於/jre/lib/ext資料夾下。介紹下所有依賴的jar包:

jar包 作用
access-bridge.jar Microsoft Windows作業系統的Java Access Bridge使基於Windows的輔助技術可以與Java Accessibility API進行互動;
charsets.jar 擴充套件的字符集。rt.jar中sun.nio.cs包下為基礎的字符集;
cldrdata.jar 資料標準庫,用於資料的國際化和本地化。可見:cldr官網
deploy.jar 用於部署應用的執行安裝程式;
dnsns.jar 處理DNS服務,暴露lookupAllHostAddr(),getHostByAddr()方法,用於InetAddress;
jaccess.jar Java Accessibility Utilities實用程式類的一部分,可幫助輔助技術提供對實現Java Accessibility API的GUI工具包的訪問;
javaws.jar JNLP協議,支援Java Web Start應用,可以直接通過瀏覽器執行Java應用程式;
jce.jar 擴充套件的加密包;
jfr.jar Java飛行記錄器,是JMC的一個重要組成部分,用於記錄JVM和執行的Java程式的診斷資料、分析資料。對效能影響小於1%;
jfxrt.jar JavaFX的執行時核心jar包,相當於rt.jar
jfxswt.jar 為JavaFX和Swing提供相容性操作
jsse.jar 用於驗證SSL連線的jar
localedata.jar 國際化的資料
management-agent.jar 只有MANIFEST.MF一個檔案,用於VisualVM或者JConsole等工具的代理jar包;可檢視實際應用介紹
nashorn.jar Java嵌入式的JS引擎,可以實現js與Java的相互呼叫,還可以使用jrunscript命令執行js;
plugin.jar 用於各種使用場景的外掛jar包
resources.jar 用於各種使用場景用到的靜態資源,如.properites,.png,.css,.txt等檔案

rt.jar

Java的runtime執行時核心程式碼包

sunec.jar,sunjce_provider.jar,

sunmscapi.jar,sunpkcs11.jar

加密相關的jar包

zipfs.jar

支援對zip壓縮包檔案操作

rt.jar介紹

Java SE版本涉及的基礎核心類庫,原始碼則可以將jdk的src.zip解壓後檢視。但是並非rt.jar中的所有包都是有原始碼的。不知道具體原因是什麼,有沒有了解的童鞋評論下點撥下。

具體API都可以在https://docs.oracle.com/javase/8/docs/api/index.html檢視,或者下到電腦自行檢視,不同版本的API直接將"/8/"變更成你需要的Java版本即可。

接下來介紹下組成架構圖中Java SE規範除去UI Toolkits的模組以及功能。

模組 API規範 功能
lang and util

java.lang.*

java.util.*

提供幾乎所有Java應用程式的基本功能
Math

java.lang.Math

java.lang.StrictMath

java.math

浮點數計算,數學公式計算
Management

java.lang.management

java.util.logging.LoggingMXBean

javax.management

com.sun.management

com.sun.tools.attach

com.sun.tools.jconsole

提供JVM、JConsole、JMX、日誌等監控管理功能
Versioning

java.lang.Class

java.lang.ClassLoader

java.lang.Package

java.lang.System

提供Class、Package管理功能
Ref Objects java.lang.ref 引用物件提供與GC有限互動功能
Reflection java.lang.reflect 反射提供從JVM中檢視載入類、修改物件的功能
Collections

基於java.util.Collection的實現

基於java.util.Map的實現

提供了功能強大、設計優秀的集合操作功能
Concurrency Utilities java.utl.concurrent 提供了強大且易擴充套件的高併發解決方法
JAR

java.util.jar

java.net.JarURLConnection

提供了Jar檔案的處理功能
Logging java.util.logging 提供對日誌記錄的處理和互動
Preferences API java.util.prefs 提供對使用者和應用的首選項處理功能
Instrumentation

java.lang.instrument

用於工具來檢測Java程式語言應用程式
Regular Expressions

java.util.regex

正規表示式
ZIP

java.util.zip

用於讀取和寫入標準ZIP和GZIP檔案格式
Input/Output

java.io

java.nio

com.sun.nio

提供針對檔案和裝置I/O處理的豐富功能
Serialization java.io 提供Java物件的序列化和反序列化功能
Networking

java.net

javax.net

com.sun.net

jdk.net等

提供用於網路處理的功能,包括定址、連線、安全等
Security

java.security

javax.crypto

javax.rmi.ssl

javax.xml.crypto

javax.smartcardio

com.sun.security

org.ietf.jgss等

用於與安全相關的功能的API,如訪問控制,數字簽名,身份驗證和授權,加密等
Internationalization

java.util.spi

java.util.Locale

java.text.DecimalFormatSymbols等

支援開發國際化應用程式的API,可以在不進行工程更改的情況下適應各種語言和地區。
Beans

java.beans

java.beans.beancontext

主要提高了互動性和可維護性,JavaBeans的長期永續性可以讀寫bean作為其屬性值的文字表示形式
JMX  javax.management  Management Extension管理擴充套件,用於管理和監控資源使用
 XML JAXP

javax.xml

org.w3c.dom

org.xml.sax

 用於處理XML文件和資料
JNI   用於編寫Java本機方法並將Java虛擬機器嵌入本機應用程式的標準程式設計介面,可以實現Java與其他語言的互動。推薦一篇介紹如何使用JNI的文章
Extension Mechanism   支援擴充套件,jar包置於/jdk/jre/lib/ext,二進位制檔案置於/jdk/jre/bin,JVM會作為可信任檔案載入,不做安全檢查。已棄用,未來版本刪除此功能
Override Mechanism   除JCP外定義的Java API,可以覆蓋成新版本作為認可標準版本。未來版本刪除功能
IDL

org.omg.CORBA

org.omg.CosNaming

org.omg.PortableServer

org.omg.PortableInterceptor

org.omg.DynamicAny

使分散式、支援Web的Java應用可以基於IIOP協議透明地呼叫遠端服務
JDBC

java.sql

javax.sql

通用資料訪問介面,需要驅動進行連線。如常用的mysql-connector-java.jar
JNDI

javax.naming

提供命名和目錄功能,以通用方式訪問各種服務。如Spring定義的jndi-lookup可以用於Wildfly部署的應用程式來建立資料庫連線
RMI

java.rmi

提供呼叫遠端JVM中的Java物件的方法,使用物件序列化來封裝和解析
RMI-IIOP

org.omg.CORBA

org.omg.CosNaming

org.omg.PortableServer

javax.rmi

通過Internet Inter-ORB協議技術進行Java遠端方法呼叫RMI程式設計模型可通過RMI API進行CORBA伺服器和應用程式的程式設計。
Scripting

javax.script

指令碼引擎介面,可以實現動態指令碼與java的互動,Java SE套件中含有nashorn引擎,可見nashorn.jar

JDK提供的工具

所有提供的工具按照類別分組情況如下,具體的使用方法可以下載JDK的文件檢視。

  • 基本工具 (appletviewer, extcheck, jar, java, javac, javadoc, javah, javap, jdb, jdeps)
  • 安全工具 (keytool, jarsigner, policytool, kinit, klist, ktab)
  • 國際化工具 (native2ascii)
  • RMI工具 (rmic, rmiregistry, rmid, serialver)
  • Java IDL和RMI-IIOP工具 (tnameserv, idlj, orbd, servertool)
  • 部署工具 (javapackager, pack200, unpack200)
  • Java Web Start工具 (javaws)
  • 故障排除,效能分析,監視和管理工具 (jcmd, jconsole, jmc, jvisualvm)
  • Web服務工具 (schemagen, wsgen, wsimport, xjc) 

Java 9及以後

上述的組成架構圖,是基於Java 8的解析。在Java9前,由於之前JRE必須要整體部署執行,會造成一定程度不期望的效能影響或者資源消耗。Oracle公司針對這方面的考慮,在JCP組織上做了很多的工作,終於在Java 9上實現了模組化。

Java 9之前是通過不同的package和jar對功能做區分隔離,Java9後,可以通過不同的module進行隔離。

如果開啟JDK 9後資料夾,你會發現jre資料夾不存在了,出現了新的資料夾:jmods。資料夾下面的每個檔案都是一個元件,每個元件都會有一個module-info.class檔案。開啟檔案你會發現,存在著類似nodejs等語言常用的關鍵字:用requires引入需要的元件、 用exports暴露的包名;其中java.base是最基礎的模組,其他元件不需要顯示requires。

module java.sql {
    requires transitive java.logging;
    requires transitive java.transaction.xa;
    requires transitive java.xml;

    exports java.sql;
    exports javax.sql;

    uses java.sql.Driver;
}

筆者也還未曾使用過Java 8以後的版本編寫過專案,童鞋們有沒有優秀的文章分享分享呢?

總結

通過上述的篇幅,我們可以知道:

1. JVM在JRE(JDK)中是以動態連結庫的形式存在的,windows中是jvm.dll,linux中是libjvm.so

2. JDK 8有3種實現的compact JRE,數字越大,功能越豐富

3. 組成架構圖中的Java SE API部分,位於/jre/lib和/jre/lib/ext資料夾下jar包中

4. rt.jar包是Java SE最為核心的包

5. 組成架構圖中的Tools部分,位於jdk的bin目錄下的可執行的二進位制檔案

6. JDK 9後 Java SE API不再是以jar形式存在,而是.jmod檔案,針對不同的功能進行模組化

 

現在對JDK的組成結構到實際開發運用是否有了進一步理解呢?有疑問的地方,歡迎童鞋們留言討論! 

 

參考文章:

1. https://blog.csdn.net/topdeveloperr/article/details/89789132#jdk%E5%8C%85%E6%80%BB%E8%A7%88

2. https://segmentfault.com/a/1190000022711960