探秘Java9

2017年9月Java9正式发布,之前就一直听说新版会有模块化,仔细了解下Java9的发展史,这个模块化确实比较坎坷,当然,好事多磨嘛。

1、相关组织

JUG:Java User Groups(Java用户群),以下是JUG官方提供的组织列表,其中有两个是大陆的,一个在南京,一个在杭州,之前在南京时参加过南京JUG组织的活动。

探秘Java9探秘Java9

JCP:Java Community Process,一个促进Java发展的国际组织,主要负责JSR的制定,OpenJDK的开发。其中JUG属于JCP。

EC:Executive Committee,是JCP中的执行委员会,是选举产生的,但Oracle是终身的执行委员会(没办法,因为JCP也是由SUN(后被Oracle并了)发起的),主要负责JSR的制定,有投票权。这里列一下曾经的EC成员:Motorola、Nokia、Sony、Samsung、HP、Siemens、Texas Instruments、Apple、Philips、Symbian、JBoss、Google、Ericsson、BenQ、SpringSource、AT&T、VMWare、Aplix、Freescale、Apache、Doug Lea、Timothy Peierls。

2、相关名词

JEP:JDK Enhancement Proposals(JDK增强建议),来源于JCP社区,但不一定被采纳。

JSR:Java Specification Requests(Java规范请求),JSR是有状态的,并不是所有的JSR都有效,所以在看JSR时需要先看下状态是否有效。Java的各个版本的语言规范和虚拟机规范都是JSR范畴里的,JSR的生效由Expert Group(专家组)商讨制定并由EC投票确立。JSR的确立是有一个具体流程规范的,不过并不是所有的JSR都会在JDK里实现的。

JSR专家组(Expert Group):从JCP里选出的对应领域有威望的个人(其实背后代表的是所属公司),负责制定和修改JSR。其中Java9对应的JSR379的专家组如下:

探秘Java9

Java语言规范:其实已经包括在JSR里,细分开是因为只是语言层面的,不涉及跨平台的JVM的细节,所以想要详细了解Java语法的可以仔细研读下。具体代码里如何实现的不在规范里。

JVM规范:这里主要描述虚拟机的实现规范,包括指令集及其作用、虚拟机内存模型、类文件描述、编译、链接、加载、初始化等步聚描述,想要了解虚拟机具体是怎么工作的可以仔细研读下,不过规范不涉及实现,目前虚拟机的实现也有很多种,HotSpot是OpenJDK里的,想要了解实现细节的可以下载HotSpot源码看下。

3、JDK功能的由来

通过上面的一些简介可以大致看出,JDK的功能来源于Java开发者在实际使用时发现的一些不足之处,然后以JEP的方式反馈给社区,社区再通过专家组收集并制定JSR,再由EC投票是否要采纳,对于规划到Java版本JSR里的再由JCP分配或认领开发实现,经过一系列测试验证后发布Release版本。

4、JSR376:JPMS

Java9的规范是JSR379,但379又依赖JSR376,也就是Java的平台模块化,在JDK9的源码里也可以看到“@spec JPMS”,这个表示的是这块代码是JSR376里要求实现或修改的。

5、JSR 379: JavaTM SE 9 Release Contents涉及哪些JEP?

个人根据JSR文档整理了下,共涉及91个JEP,其中8个JEP是关于废弃的,39个JEP是关于修改的,44个JEP是关于新增的,模块化涉及8个JEP,安全涉及7个JEP。可以看出Java9不仅仅是模块化,还带来很多其他的改变,具体整理JEP如下(前辍说明:U:修改,A:新增,D:废弃,M:模块化,S:安全):

U  102: Process API Updates
A  110: HTTP 2 Client
U  143: Improve Contended Locking
U  158: Unified JVM Logging
U  165: Compiler Control
U  193: Variable Handles
U  197: Segmented Code Cache
U  199: Smart Java Compilation, Phase Two
AM 200: The Modular JDK
AM 201: Modular Source Code
A  211: Elide Deprecation Warnings on Import Statements
A  212: Resolve Lint and Doclint Warnings
U  213: Milling Project Coin
D  214: Remove GC Combinations Deprecated in JDK 8
A  215: Tiered Attribution for javac
U  216: Process Import Statements Correctly
U  217: Annotations Pipeline 2.0
A  219: Datagram Transport Layer Security (DTLS)
AM 220: Modular Run-Time Images
A  221: Simplified Doclet API
A  222: jshell: The Java Shell (Read-Eval-Print Loop)
A  223: New Version-String Scheme
U  224: HTML5 Javadoc
A  225: Javadoc Search
A  226: UTF-8 Property Files
A  227: Unicode 7.0
A  228: Add More Diagnostic Commands
US 229: Create PKCS12 Keystores by Default
D  231: Remove Launch-Time JRE Version Selection
U  232: Improve Secure Application Performance
A  233: Generate Run-Time Compiler Tests Automatically
A  235: Test Class-File Attributes Generated by javac
A  236: Parser API for Nashorn
A  237: Linux/AArch64 Port
U  238: Multi-Release JAR Files
D  240: Remove the JVM TI hprof Agent
D  241: Remove the jhat Tool
A  243: Java-Level JVM Compiler Interface
US 244: TLS Application-Layer Protocol Negotiation Extension
U  245: Validate JVM Command-Line Flag Arguments
US 246: Leverage CPU Instructions for GHASH and RSA
U  247: Compile for Older Platform Versions
U  248: Make G1 the Default Garbage Collector
AS 249: OCSP Stapling for TLS
U  250: Store Interned Strings in CDS Archives
A  251: Multi-Resolution Images
U  252: Use CLDR Locale Data by Default
A  253: Prepare JavaFX UI Controls & CSS APIs for Modularization
U  254: Compact Strings
U  255: Merge Selected Xerces 2.11.0 Updates into JAXP
U  256: BeanInfo Annotations
U  257: Update JavaFX/Media to Newer Version of GStreamer
U  258: HarfBuzz Font-Layout Engine
A  259: Stack-Walking API
UM 260: Encapsulate Most Internal APIs
AM 261: Module System
U  262: TIFF Image I/O
A  263: HiDPI Graphics on Windows and Linux
A  264: Platform Logging API and Service
U  265: Marlin Graphics Renderer
U  266: More Concurrency Updates
A  267: Unicode 8.0
A  268: XML Catalogs
A  269: Convenience Factory Methods for Collections
U  270: Reserved Stack Areas for Critical Sections
U  271: Unified GC Logging
A  272: Platform-Specific Desktop Features
A  273: DRBG-Based SecureRandom Implementations
U  274: Enhanced Method Handles
AM 275: Modular Java Application Packaging
AM 276: Dynamic Linking of Language-Defined Object Models
U  277: Enhanced Deprecation
A  278: Additional Tests for Humongous Objects in G1
U  279: Improve Test-Failure Troubleshooting
U  280: Indify String Concatenation
A  281: HotSpot C++ Unit-Test Framework
AM 282: jlink: The Java Linker
A  283: Enable GTK 3 on Linux
U  284: New HotSpot Build System
A  285: Spin-Wait Hints
AS 287: SHA-3 Hash Algorithms
DS 288: Disable SHA-1 Certificates
D  289: Deprecate the Applet API
AS 290: Filter Incoming Serialization Data
D  291: Deprecate the Concurrent Mark Sweep (CMS) Garbage Collector
A  292: Implement Selected ECMAScript 6 Features in Nashorn
A  294: Linux/s390x Port
A  295: Ahead-of-Time Compilation
U  297: Unified arm32/arm64 Port
D  298: Remove Demos and Samples
U  299: Reorganize Documentation

6、Java9带来哪些变化?

通过5中的JEP也可以看出有9带来了哪些变化,不过官方还是给了一个分类如下:

探秘Java9

主要分为:平台、语言、核心库、网络、安全、客户端库、拓展标记语言 这7类。

7、关于模块化

因为Java9对于平台来说最大的变化是模块,涉及到了语法规范和虚拟机的改变,具体有哪些变化呢?其实规范里这些都特意标出来了,按照常规的思考应该类加载会变,还要就是要么像OSGI那样用MANIFEST.MF,要么就新增加一些关键字。实际是增加了一个module-info.java文件,这个有点像已经有的package-info.java,不过package-info.java其实只起到注释包的作用,并没有什么新的关键字,所以没有语法不兼容的情况,但module-info.java则不同了,个人感觉和OSGI里的MANIFEST.MF里的一些用法并没有什么不同,但这样会导致IDE识别不了这些关键字,编译器就需要有对应的修改才能正常兼容。

其实模块化这个想法早在十几年前就已经提出来了,而且也有对应的JSR,因为在构建大型的Java应用时会因为使用的Jar有多个版本,根据路径加载的方式会出现不可控的情况,也就是我们常见的类冲突,因为不同的环境可能会导致不同的类加载顺序,而Java对于相同包名类名的类加载只有第一次生效,后面的不会再加载,所以对于大型系统的复杂依赖这个问题比较严重。还有就是生成的应用越来越大,在嵌入式应用中不太适合。而OSGI最开始也不是模块化的代名词,其实OSGI最开始创立的目的应该是像JCP一样,制定一些网关设备相关规范的,那时Java在嵌入式领域也有了广泛的应用,当时看到了Java的不足,提出来JSR291,这才诞生了OSGI框架,经过十多年的发展,已经相当成熟。

不过JSR376也说明了自己与JSR291的区别,JSR291是在平台之上的,不是平台具备的能力,JSR376的目的是让平台具有模块化的能力,同时平台的模块化能力也能够直接给OSGI框架使用,毕竟OSGI的核心是动态加载的框架。

8、其他关于模块化的应用

OSGI:为什么OSGI可以直接基于现有的JDK达到模块化?其实这个依赖于Java的类加载机制,不同的ClassLoader是可以让同一个类有多个版本加载的,但同一个ClassLoader不能对同一个类的多个版本进行加载。

Pandora:其实这个我觉得应该算是模块化的产物,如果十多年前模块化被纳入JDK,也不会有Pandora了吧。实现的原理也是基于类的加载和对应的ClassLoader有关。

Maven:也算是模块化的应用吧,不过是以pom.xml的方式来管理依赖的,对于冲突也是在pom.xml的依赖管理里来排,但对于像OSGI和Pandora那样的类加载方式却不涉及,完全靠人肉排除多版本依赖的问题。不过我想Maven的目的并不仅仅是解决这个问题的,Maven主要还是管理依赖和jar包分发,从更上层来避免此类冲突问题。

上一篇:阿里云开启共享带宽新时代【一】:所有ECS都可以用共享带宽节省成本


下一篇:报名通道开启!原生安全二倍速:探秘基础设施的内生“免疫系统"