OSGi,Java模块化框架的另类进化(1)

OSGi,Java模块化框架的另类进化(1)


我们曾不只一次的听到2010年将是Java模块化的一年的言论;也知道目前为Java提供模块化的OSGi正在受到IBM和Eclipse基金会的大力支持。但作为实现Java模块化应用的基础框架,OSGi似乎并不完美;我们经常能听到关于OSGi过于复杂的抱怨。

从个人的角度,我以开放的心态去了解OSGi。令人失望的是,我发现它的规则非常复杂而且是低阶的(low-level),对于大多数企业 Java 环境,需要对其进行许多改善/缩写的工作,才能让它更容易被人理解。对于大多数实际的企业需求,它又显得功能过于强大。比较而言,Jigsaw 感觉更“干净”,以 Java 为中心,紧凑而且易于理解。

说实话,这种抱怨让我有点困惑。我来假设一下,如果OSGi 现在并不存在,有人给我一项任务,为Java 平台设计一个新的模块系统,那么对于这个模块系统的最合理的需求集合将直接指向OSGi,因为OSGi的设计目的可能是满足我们需求的最简单的解决方案。

是不是我的想象力不够?或者这不过是爱因斯坦剃刀原理(事物应尽可能简单而不是更简单)打败奥卡姆剃刀原理(如无必要,勿增实体)的又一个实例?

另外,我认可OSGi 初看并不是那么简单这一说法,尤其是你不了解它为什么会是现在这样的时候。

OSGi框架的各个组成部分 
OSGi框架的各个组成部分

在这篇文章中,我将按照上述的那个假设,从零开始设计OSGi 系统。当然许多细节问题在这里我不能一一讲述。下面切入正题,为什么OSGi 成为现在这个样子?我们一起看看OSGi不算漫长但足够复杂的进化(这种进化是积极的,因为它为解决业界实际存在的问题而生)。


模块分离

我们的第一个需求是清晰地划分模块,这样一个模块中的类就不会具有我们无法控制的功能:使用或覆盖另一个模块中的类。在传统的 Java 中有一个“classpath”(类路径),这是一个巨大的类列表,当多个类碰巧使用相同的名称时,总是使用第一个类,而第二个和其他所有的同名类将被忽略。看起来这种事情不会经常发生,当事实并非如此。当存在许多库而这些库又依靠其他库时,这个问题就变得常见了。这个覆盖问题绝对是致命的,因为它会导致一些奇怪的错误,比如 LinkageError、IncompatibleClassChangeError 等。事实上能够看到这些错误,那还是比较幸运的。倒霉的是这些错误没有提示,而系统一声不响地错误地运行,哪怕在部署之前我们做了许多先行测试。

对于类的覆盖和不可能空的可见性,预防方法是为每一个模块创建一个类加载器(class loader)。类加载器能够做到仅加载它能够直接识别的类,在我们的这个系统中,就是某个模块的内容(不过,它也可以根据类对类的方式,请求其他类加载器提供类,这种方式称为委派,即 delegation)。使用类加载器之后,每个模块包括他需要处理的代码和类,而且能够保证获得按照计划应该使用的类,即使系统中的其他模块包含同名的类。

从整体上恢复可见性等功能

完成以上步骤之后,我们到达这样一个点:所有模块完全隔离,无法互相通信。为了让这个系统变得实用些,我们需要恢复一些功能,以便能够看到其他模块中的类,不过这样做时必须非常谨慎,而且必须使用严格控制的方式。这里我们又多了一个需求:模块需要能够隐藏某些部署细节。

在 Java 中,protected/默认和 public 类型之间缺少访问修饰符。假设我写了一个库,希望这个库中其他包能够使用我的一个类,我必须让这个类设置为 public。但这样这个类将对所有人是可见的,包括这个库外部的客户,这些客户将能够直接使用我的内部类。我们想要的是一个“模块”级的访问级别,但现在的问题是 javac 编译器无法区分模块边界在哪里,因此对于这样的访问修饰符它无法执行任何检测。事实上,现有的“默认”访问修饰符也是有问题的,因为它应该只对同一个“运行时包(runtime package,即由某个特定类加载器加载的包)”提供访问权。但同样 javac 无法确定运行时存在哪些加载器。对于这种情况,javac 会采取冒险的方式:即使之后会导致 IllegalAccessErrors 错误,它也会提供访问权。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值