本文的英文原文Modularized Java with JBoss Modules是JBoss Modules的作者David写的,由HollisChuang翻译在使用JBoss Modules来模块化Java中。转载请注明出处!!!
一年前Mark Reinhold(Sun/Oracle的顶尖Java工程师之一)在JavaOne上宣称“classpath已死”,在之后它又写了一系列的文章来阐述这一观点,并且宣告Java的未来是模块化。与此同时,JDK7的发布已经大幅推迟,我们可能在2012,或以后才能见到JDK中java模块的实现。而JSR294的参与人员一直是走走停停,缓慢的寻求一个和java语言结合紧密的java模块化标准,这可能是因为需要语言,二进制代码和打包方面的支持。
我一直在想商讨起草一个可用而且不错的模块化标准用不了这么长时间。我用在JBossAS7概念证明(proof-of-concept)时创建的JBoss Modules证明了我的想法。
如果你没有关注JDK7的发展,你可能都不知道自己错过了这个概念。
模块由一些类、资源集合而成,并且关联一个类加载器。一模块可以依赖另外一个模块。 从被依赖的模块里导出(export)的类和资源对于依赖它的模块里边的类是可见的(visible)。可见是指一个类加载器里加载的类能够“看到”另外一个加载器里的类(译者注:其实就是可以调用其api)。导出(export)一个类或者资源意味着这个类可以被依赖看到。
所以一个模块系统提供一种方法将类和资源打包成为模块,并且在运行时建立一个类加载的图表,这样所有表达的依赖关系都可以被这个模块系统实现。
在Java中运行应用程序的传统方法是使用著名的classpath机制。它会创建一个application的类加载器,并且把所有相关jar文件资源汇聚到一起成为一个大块(blob)。
假如你有一个非常庞大的应用,其中包含了很多的jar文件,并且有些jar在可能根本不会被用到,或者有些jar会有多个相互冲突的不同版本。这些问题我们习惯性的称之为”JAR Hell“. (译者注:有过web开发经验的都知道,很多classNotFound类型的错误都是由于jar包冲突或者版本不一致导致的)
模块可以极大的缓解这个问题。如果所有的jar都打包成为模块,一个jar再也不会看到依赖里一个冲突版本的类,或者加载到一个根本不需要加载的资源。同时,如果一个模块用到才被加载能够极大的提高大型应用的启动时间。
JBoss Modules是一个独立的运行在JDK6及以上版本的模块系统。它支持以下特性(或者更多):
1、高效的使用内存,提供高性能,多线程类加载实现, 在o(1)的时间复杂度内加载任何的类和资源。
2、可扩展的模块加载系统,允许用户配置其他可替代实现的模块定义/加载策略。
3、方便使用的本地模块加载器,能够用一种简单的可预测的结构从文件系统上加载Jar文件,或者是展开的目录
4、简单的启动过程(参看以下内容)
5、提供一系列运行时的API ,通过这些API可以加载模块,获得模块的类加载器,在运行时创建模块,扩展JDK service加载机制,使其成为一个能够识别模块,
6、能够提供对平台native代码更多的管理。
一个模块化程序使用以下命令启动:
java -jar jboss-modules.jar -mp path/to/modules my.main.module.name
在模块路径(-mp)中需要制定默认模块加载器需要搜素加载模块的根目录。一个模块使用简单的XML描述符进行定义,如:
<module xmlns="urn:jboss:module:1.0" name="org.jboss.msc">
<main-class name="org.jboss.msc.Version"/>
<resources>
<resource-root path="jboss-msc-1.0.0.Beta3.jar"/>
</resources>
<dependencies>
<module name="org.jboss.logging"/>
<!-- Optional deps -->
<module name="javax.inject.api" optional="true"/>
<module name="org.jboss.threads" optional="true"/>
<module name="org.jboss.vfs" optional="true"/>
</dependencies>
</module>
在jboss-moduels.jar里有一个完整的schema文件来定义模块描述符的格式,因此可以很容易的IDE里面定义这样的文件。JBoss Moduels提供了很多扩展的功能去严格控制
哪些包可以被导出(export)和导入(imported),所以你可以从你的 Jar文件里选择性的不包含一些资源(这样使用预打包的jar文件时将变得更为简单)