码农飞升记-05-JDK8安装包的下载安装方式以及环境变量的配置
前面我们介绍了 《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 安装包环境变量的配置
1.进入环境变量设置界面
- 单击开始菜单。
- 点击设置(Settings),进入设置界面。
单击系统(System),进入系统设置界面。
- 单击关于(About),进入关于页面。
- 点击高级系统设置(Advanced system settings),进入高级设置页面。
- 点击选中高级(Advanced)。
- 单击环境变量(Environment Variables),进入环境变量界面。
双击 Path(单击一下 Path 之后单击编辑(Edit)),进入 Path 列表。
2.删除环境变量 Path 列表中 OracleJDK 安装程序自动配置的路径
进入 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 列表的修改并返回环境变量界面。
3.设置 JAVA_HOME 系统变量
单击新建,进入新建系统变量界面。
-
填入变量名(用于区分各种变量):
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,完成新建系统变量。
- 变量名:
4.在环境变量 Path 列表中引用 JAVA_HOME
双击 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
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