前面我們介紹了 《Java是什麼?》、《OracleJDK是什麼?OracleJDK的版本怎麼選擇?》、《OpenJDK是什麼?》以及《OracleJDK 與 OpenJDK 的區別和聯絡以及 OracleJDK builds 與其他 OpenJDK builds 的選擇問題》,相信大家已經充分了解了 Java 的概念、OracleJDK 和 OpenJDK 的關係以及如何在眾多 OpenJDK builds 中選擇適合自己的 JDK builds,下面就以 OracleJDK 8 為例,講解一下 JDK 8 安裝包的下載安裝方式以及環境變數的配置。
其他 JDK 版本的下載安裝方式以及環境變數的配置:
博主用的是 Win10,所以直接用 Win10 舉例,其他系統的操作方法也是大同小異。
1.下載 JDK 8 安裝包
由於目前想要在 Oracle 官網下載 OracleJDK 都需要一個 Oracle 賬戶,沒賬戶的朋友可以需要去建立一個(後續下載 OracleJDK 的時候會用到)。
準備 Oracle 賬戶
前往 Oracle 官網,你會看到以下介面。
- 選擇單擊頁面頂部的檢視賬戶(View Accounts),在Oracle 賬戶(Oracle Account)下:
- 沒有賬戶的朋友點選建立賬戶(Create an Account),進入建立賬戶頁面。
- 有賬戶的朋友可以直接選擇單擊登入(Sign-In),進入登入頁面。
因為建立賬戶會多一個步驟,為了更好地演示,這裡博主先選擇建立賬戶。
建立 Oracle 賬戶
- 按照表格的提示填寫好對應的資訊。
- 點選建立賬戶(Create Account),返回主頁介面。
登入 Oracle 賬戶
成功建立賬戶之後,再進入登入頁面。
- 輸入使用者名稱。
- 輸入密碼。
- 點選登入(Sign in),返回主頁介面。
成功登入後會自動返回主頁。
選擇 OracleJDK 版本
進入 OracleJDK 版本頁面
單擊主頁上方的產品(Products)。
單擊選擇軟體(Software)下的 Java,進入 Java 頁面。
單擊右邊的下載 Java(Download Java),進入OracleJDK 選擇頁面。
OracleJDK 8 版本區別
雖然前面的章節中有提到,但是以防有新來的朋友不知道,這裡還是再提一下。
Java SE 8 以及之前版本的釋出節奏和不同版本的差距
根據 Java CPU and PSU Releases Explained 裡面的描述:
Which Java version should I choose: the CPU or the PSU?
Oracle strongly recommends that all Java SE users upgrade to the latest CPU release available for a release family. Most users should choose the CPU release.
Users should only use the corresponding PSU release if they are being impacted by one of the additional bugs fixed in that version as noted in the release notes.
The subsequent CPU release will contain all of the fixes from the current PSU. For this reason, organizations should test the current PSU in their environment in anticipation of these fixes being included in the next CPU.
What is the difference between a Java CPU and PSU release?
Java SE Critical Patch Updates (CPU) contain fixes to security vulnerabilities and critical bug fixes. Oracle strongly recommends that all Java SE users upgrade to the latest CPU releases as they are made available. Java SE CPU releases are odd numbered versions (i.e. 7u71, 7u65 – see more on Java SE version numbering schemes here).
Java SE Patch Set Updates (PSU) contain all of fixes in the corresponding CPU, as well as additional non-critical fixes. Java PSU releases should only be used if you are being impacted by one of the additional bugs fixed in that version. The release notes call out the additional fixes available in Java SE PSU releases.
Is the cadence of CPU releases changing?
As before, Java SE CPU releases are scheduled for release on the Tuesday closest to the 17th day of January, April, July and October under the normal Oracle Critical Patch Update schedule.
Starting in October 2014 with the release of Java SE 7u71 (CPU) and Java SE 7u72 (PSU), Oracle plans to additionally release a corresponding PSU release along with each CPU release for Java SE 7. PSU releases provide organizations and developers with access to non-critical fixes in addition to the critical fixes contained in the corresponding CPU.
1.釋出的版本區別
CPU (Critical Patch Updates):關鍵補丁更新(CPU)包含對安全漏洞和關鍵錯誤的修復。Oracle 強烈建議所有 Java SE 使用者升級到最新的 CPU 版本。Java SE CPU 版本是奇數版本(即7u71、7u65–請參閱此處有關Java SE版本編號方案的更多資訊)。
PSU (Patch Set Updates):補丁集更新(PSU)包含相應 CPU 中的所有修復,以及其他非關鍵修復。只有當您受到該版本中修復的其他錯誤之一的影響時,才應使用Java PSU版本。Java SE PSU 版本是偶數版本,版本說明中列出了Java SE PSU 發行版中提供的其他修復程式。
PS:
- Oracle 強烈建議所有 Java SE 使用者升級到一個版本系列的最新 CPU 版本。大多數使用者應該選擇 CPU 版本。
- 如果使用者受到版本說明中所述的該版本中修復的其他錯誤之一的影響,則只能使用相應的PSU 版本。
- 隨後的 CPU 版本將包含當前 PSU 的所有修復程式。因此,組織應在其環境中測試當前 PSU ,以預期這些修復將包含在下一個 CPU中。
- 從2014年10月開始,隨著 Java SE 7u71(CPU)和 Java SE 7u72(PSU)的釋出,Oracle 計劃在 Java SE 7的每個 CPU 釋出版本的同時,額外發佈一個相應的 PSU 版本。
2.釋出週期
Java 每兩年釋出一次,直到 Java 6於2006年12月23日在 Sun 下發布為止。由於政治上的僵局,下一個版本是2011年7月28日釋出的 Java 7。
在2012年3月7日於倫敦舉行的 QCon 2012 大會上,前 Sun Microsystems 負責人、現任 Oracle Java 產品經理 Simon Ritter 承諾 Java 將回到兩年的釋出週期。
但在2013年4月18日時,Oracle 公司 Java Platform Group 首席架構師 Mark Reinhold 在部落格中表示:Oracle 計劃將 Java 8 的計劃釋出推遲到明年,理由是為了修復 Java 的安全漏洞。
3.版本的關係
版本內的更新:例如:Java 8 > Java 8u20 > Java 8u40,大多是對一些安全漏洞的修復和小型功能更新,版本間差距較小(除安全漏洞外)。
版本間的更新:例如:Java 6 > Java 7> Java 8,有較大修改、更新和安全漏洞修復,和傳統版本一樣,每一個數字的變動都是一次巨大的改革,版本間差距巨大。
2019年4月16日 以及之後釋出的 OracleJDK 版本的許可證
2019年4月16日以及之前釋出的 OracleJDK 版本是 Binary Code License
2019年4月16日以及之後釋出的 OracleJDK 版本使用的是 Java SE OTN License
因為這兩個許可證有著巨大的區別,根據這兩個許可證長篇累牘的描述結合 RednaxelaFX 在 Oracle 終於要向 Java 的非付費使用者開槍了-怎麼看?和採用java開發商業軟體需要給Oracle付錢嗎?兩個問題的回答提煉出了幾個要點。
許可證 | 免費學習 | 免費個人使用 | 免費開發 | 免費測試 | 免費商業功能 | 免費商業使用 | 免費在臺式機/筆記本上使用 | 免費在伺服器上使用 | 免費嵌入式裝置和其他計算環境上使用 |
---|---|---|---|---|---|---|---|---|---|
Binary Code License | ✘ | ✘ | |||||||
Java SE OTN License | - | ✘ | ✘ | ✘ |
PS:
- 商業功能指的是 Oracle JDK 自帶的 HotSpot VM 的啟動引數中是否有 -XX:+UnlockCommercialFeatures,如果有 -XX:+UnlockCommercialFeatures 就代表啟動了商業功能,這個功能預設是關閉狀態,需要手動開啟(在 Java 11 中被廢除)。
- Java Flight Recorder(JFR) 已經加入 Open JDK 11,在 Open JDK 11/bin 下可以直接啟動,或者在 HotSpot VM 的啟動引數中加上 -XX:StartFlightRecording。
採用 Binary Code License 的 OracleJDK 10 及其之前的版本(包含OracleJDK 8u201/8u202及其以前版本,不包含 OracleJDK 8u211/8u212及其以後版本),個人使用和商用幾乎是免費的(不使用商業功能和嵌入式裝置的情況下)。
採用 Java SE OTN License 的 OracleJDK 11 及其之後的版本(包含 OracleJDK 8u211/8u212及其以後版本,不包含 OracleJDK 8u201/8u202及其以前版本),個人使用免費,商用就要購買許可證才可以(雖然可以偷偷商用,不過那種操作就跟裸奔過雷區一樣,你也不知道啥時候會灰飛煙滅,也不知道 Oracle 會不會等養肥了再宰。若想使用免費商用的 Java 11及其之後版本,可以使用其他廠商提供的 OpenJDK builds,參考---OpenJDK是什麼?)。
選擇適合自己的 OracleJDK 8 版本
如果是選擇使用 Binary Code License 的版本就比較麻煩,因為要下載的是歷史版本而不是最新版本,所以需要滑到頁面最下面:
- 選擇單擊 Java 歸檔檔案(Java Archive) 下的 Java Archive,進入歸檔檔案選擇頁面。
如果是選擇使用 Java SE OTN License 的版本:
- 直接單擊 Java SE 8 下的 OracleJDK 下的 JDK下載(JDK Download),進入正式下載頁面。
因為下載歷史版本會多兩個步驟,為了更好地演示,博主這裡選擇進入歸檔檔案選擇頁面(可以自行選擇適合自己的 OracleJDK 8 版本,每個 OracleJDK 的正式下載頁面都是幾乎一樣的介面,不必特意跟著博主走,選擇適合自己的版本就好)。
進入了 Oracle Java 歸檔檔案選擇頁面,可以看到螢幕中央有 Java SE 8(8u202 and earlier) 和 Java SE 8(8u211 and later)。這就是我們之前說的 OracleJDK 中採用不同許可證的兩個部分,而我們特意進入歸檔檔案裡面來找,自然找的是使用 Binary Code License 的版本,也就 Java SE 8(8u202 and earlier) 。
單擊 Java SE 下的 Java SE 8(8u202 and earlier),進入正式下載頁面。
到了正式下載頁面。
注意在正式下載頁面裡有以下選項:
- Java SE Development Kit: Java SE 開發工具包
- Java SE Runtime Environment: Java SE 執行時環境
- Server JRE (Java SE Runtime Environment): 伺服器使用的 Java SE 執行時環境
我們要找的是: Java SE Development Kit
至於是下載 Java SE Development Kit 8u201(上面提到的 CPU 版本) 還是 Java SE Development Kit 8u202(上面提到的 PSU 版本) 或者其他版本,由君自行決定(後續的安裝方式都是相同的)。
選擇與自己的作業系統相匹配的版本,點選下載圖示。
- 在彈出的對話方塊中勾選接受協議。
- 點選下載按鈕。
如果沒有提前登入 Oracle 賬戶的話,這裡點選了下載之後會跳轉到登入頁面,然後成功登入 Oracle 賬戶之後會自動開始下載。
如果在一開始登入了 Oracle 賬戶的話,這裡點選下載,會直接開始下載。
現在等待 OracleJDK 下載完成即可,在等待它下載的期間,可以先繼續往下檢查環境變數情況。
2.安裝 JDK 8 安裝包
在正式安裝 JDK 之前,要先檢查一下電腦的環境變數。
檢查環境變數 Path 列表
- 單擊開始選單。
- 點選設定(Settings),進入設定介面。
單擊系統(System),進入系統設定介面。
- 單擊關於(About)。
- 點選高階系統設定(Advanced system settings),進入高階設定頁面。
- 點選高階(Advanced)。
- 單擊環境變數(Environment Variables),進入環境變數介面。
雙擊 Path(單擊一下 Path 之後單擊編輯(Edit)),進入 Path 列表。
檢查 Path 列表已有的路徑中是否有包含 Java 的路徑:
- 如果 Path 列表已有的路徑中有包含 Java 的路徑,則代表當前計算機曾經配置過 Java,根據 Path 列表中的路徑,去找到對應資料夾:
- 如果對應資料夾記憶體在 Java 相關檔案,則代表當前計算機已經配置了 Java 版本(自行決定是否需要再多安裝配置一個 Java 版本,或是將以前的 Java 解除安裝重新安裝)。
- 如果需要再多安裝配置一個 Java 版本---JDK多環境變數配置
- 如果需要解除安裝 Java 版本
- JDK 安裝包版本
- 在計算機的應用程式設定中解除安裝環境變數 Path 列表已有的路徑中有包含 Java 的路徑所指的 JDK。
- 刪除環境變數 Path 列表中的該失效路徑(環境變數 Path 列表已有的路徑中有包含 Java 的路徑)。
- JDK 壓縮包版本
- 進入環境變數 Path 列表已有的路徑中有包含 Java 的路徑,將該路徑下所有檔案刪除。
- 刪除環境變數 Path 列表中的該失效路徑(環境變數 Path 列表已有的路徑中有包含 Java 的路徑)。
- JDK 安裝包版本
- 如果對應資料夾不存在或者資料夾內沒有 Java 相關檔案,則代表當前計算機沒有配置 Java,但曾經安裝/配置過 Java。建議刪除該失效路徑(環境變數 Path 列表已有的路徑中有包含 Java 的路徑):
- 單擊選中該路徑
- 點選右側的刪除(Delete),刪除該路徑。
- 如果對應資料夾記憶體在 Java 相關檔案,則代表當前計算機已經配置了 Java 版本(自行決定是否需要再多安裝配置一個 Java 版本,或是將以前的 Java 解除安裝重新安裝)。
- 如果 Path 列表已有的路徑中沒有包含 Java 的路徑,則代表當前計算機沒有配置 Java。
關閉已經開啟的這些視窗,清空桌面(不是移開水杯,擦桌子之類的哦!)準備安裝 OracleJDK。
在檢查了環境變數之後,我們要需要了解一下 OracleJDK 8 的安裝結構。
OracleJDK 8 的安裝目錄中的兩個 JRE
OracleJDK 8 的預設安裝目錄結構為:
看了上面的結構圖,熟悉 Java 的朋友心裡肯定已經充滿了問號。為什麼 OracleJDK 8 的安裝目錄下會有兩個 JRE 呢?
Private JRE
安裝 JDK 時,會自動安裝一個 JRE 稱之為: Private JRE,存在於 JDK 內部,供給 JDK 使用。
因為 JDK 裡面有很多用 Java 所編寫的開發工具(如: javac.exe、jar.exe、javadoc.exe 等),它們本身執行的時候也需要一套 JRE,所以使用 Private JRE 來執行 JDK 自帶的開發工具(當然,你非要通過環境變數、不安裝 Public JRE 等其他手段,讓所有 Java 程式都使用 Private JRE 來執行也不是不行)。
Private JRE 不會被自動註冊到登錄檔中,也不會被自動新增到環境變數中。
Public JRE
安裝完 JDK 後會自動彈出一個 JRE 安裝程式,這個單獨安裝的 JRE 稱之為: Public JRE,存在於 JDK 外部。
Public JRE 是提供給不需要做 Java 開發的人使用的,可以獨立安裝使用(不依賴 JDK),用來執行普通 Java 程式(除 JDK 內自帶工具之外的 Java 程式)。
Public JRE 本質上就是在 Oracle 官網上擁有獨立安裝程式的 JRE(客戶端使用的 JRE),之所以要稱其為 Public JRE,是為了和 Private JRE 區別開。
JDK 與 Public JRE 預設安裝在同一個資料夾下的不同檔案中,例如:
- JDK安裝於:
C:\Program Files\Java\jdk
- Public JRE 安裝於:
C:\Program Files\Java\jre
Public JRE 安裝時會被自動註冊到 Windows 登錄檔:
- 自動註冊一個 Java Runtime Environment 到 Windows 登錄檔: 位於
HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment
- 自動註冊一個 Java Plug in 到 Windows 登錄檔: 位於
HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Plug-in
- 自動註冊一個 Java Web Start 到 Windows 登錄檔: 位於
HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Web Start
- 自動註冊一個 Java Web Start Caps 到 Windows 登錄檔: 位於
HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Web Start Caps
- 自動註冊一個 Java Update 到 Windows 登錄檔: 位於
HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Update
Public JRE 安裝時會將 java.exe 、javaw.exe、javaws.exe 三個可執行檔案複製新增到: C:\Program Files (x86)\Common Files\Oracle\Java\javapath
(非安裝路徑)中並將其路徑新增到環境變數 Path 列表中(位於環境變數 Path 列表頂層)。
Public JRE 可以通過計算機的應用程式設定通過解除安裝來刪除,應用名通常為: Java 8 Update 更新版本號 (安裝的 Java 位數)。
Java 自動更新指的就是 Public JRE 的更新,這個更新是為了讓你的計算機能夠使用最新版本正常的執行一些 Java 程式,而如果想要升級 JDK 的版本,只能夠從官網中下載最新版本的 JDK,重新安裝配置。
當在控制檯使用 java 命令呼叫 java.exe 時執行的 JRE 是 Private JRE 還是 Public JRE
看了上面的 Private JRE 和 Public JRE 的區別,那就有小夥伴要問了,那要是在控制檯使用 java 命令呼叫 java.exe 時,執行的 JRE 是 Private JRE 還是 Public JRE 呢?
這個問題問的好,博主是在寫 Private JRE 和 Public JRE 的區別的時候才想到這個問題的,經過多番查詢相關資料和反覆實驗得出了結果。
諸位別急,容我與君慢慢道來。
具體哪個 JRE 是執行,這跟安裝完 JDK 之後配置的環境變數存在很大的關係。
當我們在控制檯輸入 java
的時候,實際上是呼叫的了 java.exe 檔案,而控制檯是去哪裡找到的 java.exe 檔案呢?---通過環境變數的 Path 列表。
環境變數的 Path 列表用於記錄控制檯指令的可執行檔案的路徑。
計算機通過環境變數的 Path 列表,從上往下的順序依次在對應的檔案路徑中搜索與控制檯輸入的指令相匹配的可執行檔案並將其執行。
所以根據環境變數的 Path 列表中的先後順序,哪個路徑內能夠更早被找到,就會執行哪個路徑裡面的 java.exe。這就完了嗎?當然沒有。
當計算機找到了一個 java.exe 就會直接執行它,然而執行了 java.exe 並不等於就完成了整個命令的執行。
實際上 java.exe 程式只是一個執行的外殼,java.exe 會去尋找與自己對應的 java.dll(JVM)(是指 Java 版本,不是指 JRE 具體的更新版本,只要在同一個 Java 版本下,任何 JRE 的更新版本的 java.dll(JVM) 都行) 以確定 JRE 路徑,然後在 JRE 中尋找 jvm.cfg(JVM的配置檔案),再根據 jvm.cfg(JVM的配置檔案) 去尋找 jvm.dll(JVM),並裝載jvm.dll(JVM),jvm.dll 無法單獨工作。當 jvm.dll 啟動後,會使用 explicit 的方法(就是使用 Win32 API 之中的 LoadLibrary() 與 GetProcAddress() 來載入輔助用的動態連結庫),而這些輔助用的動態連結庫(.dll)都必須位於 jvm.dll 所在目錄的父目錄之中。
那 java.exe 又是怎麼找的 JRE 呢?
當計算機找到並執行 java.exe 時,會先在找到 java.exe 的檔案路徑中尋找 java.dll(JVM);如果沒找到,則會去找到 java.exe 的檔案路徑的父目錄下的 jre\bin
尋找 java.dll(JVM);如果還是沒找到,則會呼叫 GetPublicJREHome 函式查詢登錄檔將: HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment
中與當前執行的 java.exe 對應的 Java 版本的 JavaHome 項中填寫的 JRE 路徑作為 JRE 路徑。如果以上三個位置都沒有找到 JRE 的路徑則會在控制檯中報錯。
上面講了那麼多,頭都看暈了,現在讓我們按照執行順序來捋一捋 java.exe 的執行流程。
控制檯中執行 java 指令時 java.exe 的執行流程
1.在環境變數 Path 列表中可執行檔案:
計算機會在環境變數 Path 列表中按照從上到下的順序依次查詢對應路徑中與 java 指令相匹配的可執行檔案(java.exe) 並執行此檔案;若未找到,則在控制檯中報錯。
2.查詢對應版本的 JRE 路徑:
java.exe 開始執行時會通過java.c(javase/src/share/bin/java.c
) 的 main 函式 java_md.c 的 GetJREPath 函式呼叫 java_md.c (javase/src/windows/bin/java_md.c
) 的 GetApplicationHome 函式調取 Windows API 函式 GetModuleFileName 來獲得當前執行的 java.exe 的絕對路徑。
擷取絕對路徑: java.exe的絕對路徑\..\..\
(離 java.exe 最近的 bin 資料夾的父目錄的路徑)作為: 當前路徑
。
再按照以下順序去尋找與自己對應的 JRE 路徑(是指 Java 版本,不是指 JRE 具體的更新版本,只要在同一個 Java 版本下,任何 JRE 的更新版本都行)。
若以下三處都未能找到 JRE 的路徑或找到的 JRE 路徑中沒有對應檔案,則在控制檯中報相應的錯誤:
當前路徑\bin
(當前執行的 java.exe 所在路徑) 內是否存在與當前執行的 java.exe 對應版本的 java.dll(JVM);如果存在,則將當前路徑
作為 JRE 路徑。當前路徑\jre\bin
(當前執行的 java.exe 所在路徑的父目錄下的jre\bin
) 內是否存在與當前執行的 java.exe 對應版本的 java.dll(JVM);如果存在,則將當前路徑\jre
作為 JRE 路徑。- 呼叫 java_md.c 的 GetPublicJREHome 函式查詢登錄檔將:
HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment
中與當前執行的 java.exe 對應版本號下的 JavaHome 項中填寫的 JRE 路徑為 JRE 路徑。
3.裝載 jvm.cfg 中指定的虛擬機器動態連線庫(jvm.dll)引數:
獲得 JRE 路徑後,通過 java.c (javase/src/share/bin/java.c
)的 ReadKnownVMs 函式去 JRE 路徑\lib\ARCH(作業系統的構架)\jvm.cfg
查詢並讀取 jvm.cfg(JVM的配置檔案),通過 java_md.c 的 GetJVMPath 函式找到 jvm.dll(JVM) 路徑。
ARCH(作業系統的構架) 的判斷是通過 java.h(javase/src/share/bin/java.h
) 的 GetArch 函式判斷的,結果通常為: i386/ia64/amd64
。
通過 jvm.cfg 獲得需要執行的 jvm.dll(JVM) 的路徑: JRE 路徑\bin\JVM 型別字串\jvm.dll
。
JVM 型別字串是由控制檯使用 java 指令呼叫 java.exe 在找到 JRE 路徑後,由 java.c 的 CheckJVMType 函式根據以下情況從 java.c 的 ReadKnownVMs 函式讀取的 jvm.cfg 的內容並返回的:
- 控制檯輸入的 java 指令時攜帶了指定 JVM 的引數時:
- 指定的 JVM 的引數為: jvm.cfg 檔案中的 jvm 名稱時(
java -J<jvm.cfg 中 JVM 名稱>
)- CheckJVMType 函式檢查 java 指令攜帶的指定 JVM 的引數,擷取
java -J
後的 JVM 名稱。 - 由 ReadKnownVMs 函式去 jvm.cfg 中查詢是否存在
CheckJVMType 函式擷取的 JVM 名稱
,若存在,則返回: jvm.cfg 中對應CheckJVMType 函式擷取的 JVM 名稱
的配置為KNOWN
的不帶 '-' 的 JVM 名稱。
- CheckJVMType 函式檢查 java 指令攜帶的指定 JVM 的引數,擷取
- 指定的 JVM 的引數為: JVM 所在資料夾的絕對路徑時(
java -XXaltjvm=<JVM 所在資料夾的絕對路徑>/java -J-XXaltjvm=<JVM 所在資料夾的絕對路徑>
)- 會直接返回
-XXaltjvm=/-J-XXaltjvm=
後面的 JVM 所在資料夾名。
- 會直接返回
- 指定的 JVM 的引數為: jvm.cfg 檔案中的 jvm 名稱時(
- CheckJvmType 函式預設返回 jvm.cfg 檔案中第一個配置為
KNOWN
的不帶 '-' 的 JVM 名稱。
4.裝載 jvm.dll 動態連線庫:
找到 jvm.dll(JVM) 的路徑後,由 java.c 的 main 函式呼叫 java_md.c 中 LoadJavaVM 函式裝載 jvm.dll 動態連線庫。
java.c 的 main 函式首先構造了一個 InvocationFunctions 結構的區域性變數內含兩個函式指標: CreateJavaVM、GetDefaultJavaVMInitArgs。
LoadJavaVM 函式先呼叫 Windows API 函式:
- LoadLibrary 裝載 jvm.dll 動態連線庫。
- 將 jvm.dll 中的匯出函式 JNI_CreateJavaVM 和 JNI_GetDefaultJavaVMInitArgs 掛接到 InvocationFunctions 變數的 CreateJavaVM 和 GetDefaultJavaVMInitArgs 函式指標變數上。
- jvm.dll的裝載工作宣告完成。
5.初始化 JVM 獲得 JNIEnv 介面:
通過 java.c 中的 InitializeJVM 函式,初始化 jvm.dll 並掛接到 JNIEnv(JNI呼叫介面) 例項。
java.c 中的 main 方法中首先定義了一個 JNIEnv 結構的指標,JNIEnv 結構中定義了許多與裝載 Class 類檔案、查詢類方法、呼叫類方法有關的函式指標變數。
InitializeJVM 會呼叫上面已掛接 jvm.dll 中 JNI_CreateJavaVM 的 InvocationFunctions 結構變數的 CreateJavaVM 方法(即呼叫jvm.dll中函式JNI_CreateJavaVM),該函式會將 JNIEnv 結構的例項返回到 main 中的 JNIEnv 結構的指標上。
這樣 main 中的 JNIEnv 指標獲取了 JNIEnv 例項後,就可以開始對 Class 檔案進行處理了。
6.呼叫 JNIEnv 例項裝載並處理 Class 檔案:
如果如果是執行 jar 檔案:
java.c 中的 main 函式會呼叫 java.c 中的 GetMainClassName 函式,該函式使用 JNIEnv 例項構造並呼叫 java 類:
java.util.jar.JarFile
中getManifest()
方法並從返回的Manifest
物件中取getAttributes("Main-Class")
的值(即 jar 中的主類):- META-INF/MANIFEST.MF 指定的 Main-Class 的主類名作為執行的主類。
- java.c 中的 main 函式會呼叫 java.c 中 LoadClass 方法裝載該主類(使用 JNIEnv 例項的 FindClass)。
如果是執行 Class 檔案:
- java.c 中的 main 函式直接呼叫 java.c 中 LoadClass 方法裝載該類(使用 JNIEnv 例項的 FindClass)。
- java.c 中的 main 函式呼叫 JNIEnv 例項的 GetStaticMethodID 方法查詢裝載的 Class 主類中的主方法 (
public static void main(String[] args)
) 方法並判斷該方法是否為 public 方法。 - 呼叫 JNIEnv 例項的 CallStaticVoidMethod 方法呼叫該 java 類的主方法。
總結
瞭解了控制檯中執行 java 指令時 java.exe 的執行流程後,我們發現執行 Java 程式的 JRE/JVM 具體是誰與執行 java
指令時攜帶的指定 JVM 的引數、配置的環境變數、登錄檔中的 JRE 的引數密切相關。
啟動 JDK 8 安裝程式
Java Development Kit(JDK) 安裝
找到之前從 Oracle 官網下載的 OracleJDK。
雙擊執行 OracleJDK 安裝包程式(單擊選中 OracleJDK 安裝包,然後右鍵開啟),進入 OracleJDK 安裝程式。
OracleJDK 8 安裝程式的歡迎介面,沒什麼說的。
直接單擊下一步(next),進入自定義設定介面。
單擊修改(Change),修改 OracleJDK 8 將要安裝到的位置,進入修改資料夾頁面,不想改也可以預設。
- 選擇 OracleJDK 8 將要安裝到的位置,並確認 OracleJDK 8 將要安裝到的位置。
- 單擊OK,再次進入自定義設定介面。
- 再次確定 OracleJDK 8 將要安裝到的位置(需要記住,後面配置環境時會用到)。
- 單擊下一步(next),進入 OracleJDK 8 安裝程式的安裝介面。
正在安裝 OracleJDK 8,此時不需要任何操作,耐心等待即可。如果有防毒軟體阻止 OracleJDK 安裝程式的操作,還請放行(阻止了的話,指不定以後會出什麼奇奇怪怪的問題)。
等待進度條走滿,OracleJDK 安裝包中的 Java Development Kit(JDK) 部分就安裝完畢了。
Java Development Kit(JDK) 部分安裝完畢之後應該就會自動彈出 Public Java Runtime Environment(Public JRE) 的安裝視窗。
Public Java Runtime Environment(Public JRE) 安裝
OracleJDK 8 的 Public JRE 安裝程式的歡迎介面,沒什麼說的。
直接單擊下一步(next),進入目標資料夾介面。
單擊修改(Change),修改 Public JRE 將要安裝到的位置,進入修改資料夾頁面。
選擇 Public JRE 將要安裝到的位置,並確認 Public JRE 將要安裝到的位置
JDK 與 Public JRE 預設安裝在同一個資料夾下的不同檔案中,例如:
- JDK安裝於:
C:\Program Files\Java\jdk
- Public JRE安裝於:
C:\Program Files\Java\jre
即便修改 JDK 和 Public JRE 的安裝路徑,也推薦將 JDK 和 Public JRE 安裝到同一個資料夾下的不同檔案中,遵從原本的相對結構可以有效避免一些不必要的 Bug 作怪。
- JDK安裝於:
單擊OK,再次進入目標資料夾介面。
- 再次確定 Public JRE 將要安裝到的位置。
- 單擊下一步(next),進入 Public JRE 安裝程式的安裝介面。
正在安裝 Public JRE,此時不需要任何操作,耐心等待即可。如果有防毒軟體阻止 Public JRE 安裝程式的操作,還請放行(阻止了的話,指不定以後會出什麼奇奇怪怪的問題)。
等待進度條走滿,OracleJDK 安裝包中的 Public Java Runtime Environment(Public JRE) 部分就安裝完畢了。
恭喜你,至此,OracleJDK 8 安裝完成。
點選關閉(Close)即可。
3.JDK 8 安裝包環境變數的配置
- 單擊開始選單。
- 點選設定(Settings),進入設定介面。
單擊系統(System),進入系統設定介面。
- 單擊關於(About),進入關於頁面。
- 點選高階系統設定(Advanced system settings),進入高階設定頁面。
- 點選選中高階(Advanced)。
- 單擊環境變數(Environment Variables),進入環境變數介面。
雙擊 Path(單擊一下 Path 之後單擊編輯(Edit)),進入 Path 列表。
進入 Path 列表,你會發現 Path 列表和 OracleJDK 8 安裝之前檢查的環境變數的 Path 列表有所不同。
Path 列表的頂層多出了一行 Java 的路徑(C:\Program Files (x86)\Common Files\Oracle\Java\javapath
),我們根據這個路徑去檢視對應位置的資料夾,可以發現在這個資料夾裡已經有了 Java 的相關檔案。
我們下載安裝 JDK,就是想使用 JDK 進行開發,說到底就是需要使用 JDK 自帶的眾多開發工具(如: javac.exe、jar.exe、javadoc.exe 等)進行 Java 開發,如果只需要執行 Java 程式的話,就只需要一個單獨的 JRE 即可。
很明顯 OracleJDK 8 安裝程式自動配置的環境變數是由後面單獨安裝的 Public JRE 配置的(用於執行已經編譯好的 Java 程式使用的),並不能達到我們下載 JDK 的目的(因為裡面只有三個和執行 Java 相關的工具),所以我們不使用 OracleJDK 8 安裝程式自動配置的環境變數,轉由我們自己配置環境變數。
- 單擊選中 Public JRE 安裝程式自動配置的環境變數。
- 點選刪除(Delete),刪除該環境變數。
- 點選OK,確定 Path 列表的修改並返回環境變數介面。
單擊新建,進入新建系統變數介面。
填入變數名(用於區分各種變數):
JAVA_HOME
,(名字可以隨意,但是要能顧名思義,一般習慣取名為JAVA_HOME
)PS:
- Windows/mac 預設環境變數不區分大小寫,Linux 預設環境變數區分大小寫。
- 不區分大小寫指: Java_Home 和 JAVA_HOME 在不區分大小寫的情況下都是一樣的效果。
填入變數值( JDK 的安裝路徑): 填寫 JDK 安裝路徑,可以點選瀏覽目錄在裡面找 JDK 安裝路徑(在該路徑下要能同時直接看到:bin、include、jre、lib 等資料夾)。
點選OK,完成新建系統變數。
(可選)如果想要讓普通 Java 程式(除 JDK 內自帶開發工具之外)使用 Public JRE 執行,可以再新建一個系統變數:
- 變數名:
JRE_HOME
(名字可以隨意,能顧名思義就行) - 變數值: 填寫 Public JRE 的安裝路徑,可以點選瀏覽目錄在裡面找 Public JRE 安裝路徑(在該路徑下要能同時直接看到:bin、lib 資料夾)。
- 點選OK,完成新建系統變數。
- 變數名:
雙擊 Path(單擊一下 Path 之後單擊編輯(Edit)),再次進入 Path 列表。
單擊新建(New),新建 JDK 路徑。
輸入:
%JAVA_HOME%\bin
- 兩個 ‘%’ 中間填入之前新建系統變數時設定的變數名。
%JAVA_HOME%\bin
表示引用系統變數所指的路徑,再拼接上 '\bin' 最後就變成了:D:\Works\BasicsRuntimeEnvironment\Java\Oracle\jdk-1.8.0_201\jdk\bin
(可選)如果想要讓普通 Java 程式(除 JDK 內自帶開發工具之外)使用 Public JRE 執行,可以再新建一個 Public JRE 路徑:
- 單擊新建(New),新建 Public JRE 路徑。
- 輸入:
%JRE_HOME%\bin
- 點選右側的向上移動(Move Up),將 Public JRE 路徑移到 JDK 路徑上面一行。
單擊OK,確定環境變數 Path 列表的修改。
接下來一路 OK 就行。
單擊OK,確定修改。
當系統屬性(System Properties)的 OK 點選完成,代表著環境變數配置完成。
4.驗證 JDK 8 安裝情況
呼叫控制檯
- 同時按下鍵盤上的 Windows 鍵 和 R 鍵,彈出執行(Run),彈出後鬆開鍵盤。
- 輸入 cmd。
- 點選OK,開啟命令提示符視窗。
在控制檯檢視 Java 版本
- 輸入:
java -version
,檢查 Private JRE / Public JRE 安裝配置是否成功(如果配置了本文環境變數配置的可選選項,那這裡檢查的就是 Public JRE 的資訊,否則檢查的就是 Private JRE 的資訊)。- 成功則會正常返回: Java 、JRE 和 JVM 的版本資訊。
- 不成功則會返回: "java -version 不是內部或外部命令,也不是可執行的程式"或者其他錯誤提示。
- 輸入:
javac -version
,檢查 JDK 配置是否成功。按照我們之前的配置的環境變數(不管是否在環境變數配置了可選選項),由於 JRE 中不存在 Javac.exe,所以這條指令一定是由 JDK 的 bin 資料夾下的 javac.exe 執行,能成功執行自然代表 JDK 配置成功。- 成功則會正常返回: Java 編譯器的版本資訊。
- 不成功則會返回: "javac -version 不是內部或外部命令,也不是可執行的程式"或者其他錯誤提示。
如果兩條指令都成功返回了對應資訊,則代表安裝圓滿完成。
如果有錯誤提示,在確定安裝沒有問題的前提下,檢查環境配置是否正確。
參考資料(排名不分先後)
Java CPU and PSU Releases Explained
CPU, PSU, SPU - Oracle Critical Patch Update Terminology Update
Change to Java SE 7 and Java SE 6 Update Release Numbers
Oracle-Java SE OTN License (Oracle Technology Network License Agreement for Oracle Java SE)
Oracle-Oracle Java SE Licensing FAQ
RednaxelaFX-Oracle 終於要向 Java 的非付費使用者開槍了-怎麼看?
RednaxelaFX-採用java開發商業軟體需要給Oracle付錢嗎?
Oracle-Java SE 8 Tools Reference for Windows
Oracle-Java SE 8 Tools Reference for Windows-java.exe
部落格園-時間-海-Java虛擬機器(一):JVM的執行機制
CSDN-johnjoe.xie-《jdk8u原始碼分析》6.1.GetJREPath
CSDN-johnjoe.xie-《jdk8u原始碼分析》6.2.ReadKnownVMs
CSDN-johnjoe.xie-《jdk8u原始碼分析》6.3.CheckJvmType ergo
CSDN-johnjoe.xie-《jdk8u原始碼分析》6.4.GetJVMPath
CSDN-@wave-java原始碼分析----jvm.dll裝載過程
部落格園-RoperLee-安裝JDK的時候為什麼會有兩個jre檔案
Oracle-JDK Installation for Microsoft Windows
Oracle-JDK Installation for Microsoft Windows-Updating the PATH Environment Variable