这个规范指定了名叫demo-spring-osgi-dao的bundle,它要导入包名为 net.krecan.spring.osgi.common中的类,并导出包名为net.krecan.spring.osgi.dao中的类。换句话说,这段声明表明其他模块只能使用net.krecan.spring.osgi.dao包。相反地,这个模块要使用的则只是 net.krecan.spring.osgi.common包,而且也可能会由OSGi来提供专门的模块负责导出这个包。当然你完全可以在导入和导出声明中定义多个包名。
需要特别注意的是,OSGi的模块化是构建在Java之上的。它不是语言的一部分!这里的模块分离虽然可以由GUI来执行,但不可以由编译器来执行。运行基于OSGi的应用时,你会需要一个OSGi的容器。这个容器可能是运行时环境的一部分,比如在Spring DM服务器中,也可能是嵌入在应用程序中的。这个容器不仅负责提供分离,也提供了其他诸如安全、模块管理和生命周期管理之类的服务。OSGi还提供大量其他有趣的特性,但这些并不是本文所要关注的。
关于JSR-277曾经有很多争议,这个JSR一度跟OSGi有部分重复。连续好几个月,双方的专家都极力辩论谁更优秀,直到JSR-277被宣布放弃,而新的模块系统将会是Java 7的一部分。
JSR-294
这个新的模块系统的第一部分就是JSR-294,即所谓的超级包。也正是这个规范阐释了Java语言的模块部分的概念。
JSR-294引入了新的可见性关键字“module”。如果一个成员拥有这样的可见性,那就意味着它只对同一模块中的成员可见。它会创建一个内部的 API,只有模块本身能调用。就此看来,“public”关键字应当只在声明一个公共的API时才用。而在其他情况下,应当使用“module”或者有更多限制的可见性关键字。当然,一旦语言中有了“module”关键字,那么模块之间的可见性限制将会由编译器来负责检查。
JSR-294也允许定义依赖性。你可以在某个给定版本中,定义某个模块依赖于另一模块。比如:
//org/netbeans/core/module-info.java
@Version("7.0")
@ImportModule(name="java.se.core", version="1.7+")
module org.netbeans.core;
最后一句表明“org.netbeans.core”模块依赖“java.se.core”的1.7版本或者更高。这类似于Maven的依赖性或者 OSGi的导入。你也可以暂时不要管这些语法,因为将来语法可能会另有变化。重要的是,这儿的依赖是在module-info.java中定义的,会被编译成class文件。而OSGi中,依赖则是在普通的文本文件中定义的。
Jigsaw项目
Jigsaw项目是这个新模块系统的第二部分。我预计它会是JSR-294特定于Sun的实现,也会是Sun JDK的模块化实现。既然创建完整的JDK模块化是有必要的,Sun就希望把标准库分装成模块。这直接简化了JRE中的内容整合。整个JRE除了Swing之外的所有内容因此都能够在移动设备上运行。它还有可能为语言引入新的标准API,而无需再等待整个平台的新版本发布。目前看起来,这个项目绝对有希望实现。
但我对此还有个担忧,那就是,专有的Jigsaw和JSR标准之间的关系并不清晰,正如Mark Reinhold所说的:
对Jigsaw的投入无疑会创建出一个简单的、低层次的模块系统,它的设计会严格地朝着JDK模块化的目标而发展。开发人员可以把这个模块系统运用到他们的代码中去,Sun对这个模块系统也会是绝对的支持,但它不会是Java SE 7平台规范的官方部分,也可能不会被其他SE 7实现所支持。
这段话说的不是很清楚,当中有很多疑问。他的意思是说创建的模块只能在Sun JRE中运行吗?还是想说,如果开发者写了“@ImportModule(name="java.se.core", version="1.7+")”,那么这个模块只能在Sun JRE中运行,而不能在IBM JRE环境中运行吗?或者他的意思是不是说Sun会以某种方式把它的JRE分割成许多模块,而Oracle会选择另外的方式去分割吗?(译者注:至少现在看来,不太会有这样的可能了,因为Oracle刚刚收购了Sun)。我们希望都不是,因为还有“编写一次,到处运行”的原则。
细究起来问题更多。我们并不清楚Jigsaw项目的主要目标是什么。据项目本身所宣布的主要目标来看,它要实现的是Sun JRE的模块化,但如果纯粹是要实现模块化的话,就不需要对语言做任何改变。Sun可以对JRE进行模块化,而不修改Java语言本身。