回首Java——再回首JDK


如果你是刚要被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

Open JDK现已作为Java版本迭代的发展标准,并且开源。而Oracle JDK只不过是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的功能,还有ZGC; OpenJDK也会附带JMC开源,当前还在开发中

如果你们公司既想应用新特性,又没有授权的话,那就使用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 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,指定对应的实现方式即可。

JDK文件组成

以windows环境的Java 8u261版本为例,针对JDK的组成架构进行解读。先来了解下解压或者安装完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官网](http://cldr.unicode.org/);
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包;可[查看实际应用介绍](https://www.cnblogs.com/huanshilang/p/12206644.html)
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的文章](https://www.jianshu.com/p/6cbdda111570)
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,jaotc)
  • 安全工具 (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文件,针对不同的功能进行模块化


原文链接:https://www.cnblogs.com/joruachan/p/13346163.html