`

OSGi使用四问

 
阅读更多

/周志明、谢小明

没有什么技术是万能的,任何一门技术都有它的适用场景和最佳实践方法。OSGi不只是一门技术,更多的是一种做系统架构的工具和方法论,如果在不适用的场景中使用OSGi,或者在适用的场景中不恰当地使用OSGi,都会使整个系统产生架构级的缺陷。因此,了解什么时候该用OSGi是与学会如何使用OSGi同样重要的事情。

每个系统遇到的业务环境都是不一样的,笔者不希望以经验式的陈述去回答“什么时候该用OSGi”或 “为什么要使用OSGi”这样的问题,而试图通过以下4个问题的讨论和利弊权衡,让读者自己去思考为什么这些场景适用OSGi

1问:OSGi能让软件开发变得更容易吗?

不可否认,OSGi的入门门槛在Java众多技术中算是比较高的,相对陡峭的学习曲线会为第一次使用OSGi开发系统的开发人员带来额外的复杂度。

OSGi规范由数十个子规范组成,包含了上千个不同用途的API接口。OSGi规范显得这样庞杂的主要原因是实现“模块化”本身需要解决的问题就非常多。模块化并不仅仅是把系统拆分成不同的块而已—这是JAR包就能做的事情,真正的模块化必须考虑到模块中类的导出、隐藏、依赖、版本管理、生命周期变化和模块间交互等一系列的问题。

鉴于OSGi本身就具有较高的复杂度,“引入OSGi就能让软件开发变得更容易”无论如何是说不通的,小型系统使用OSGi可能导致开发成本更高。但是这句话又不是完全错误的,随着系统不断发展,在代码量和开发人员都达到一定规模之后,OSGi带来的额外成本就不是主要的关注点了,这时候的主要矛盾是软件规模扩大与复杂度随之膨胀间的矛盾。如下图所示,代码量越大、涉及人员越多的系统,软件复杂度就会越高,两者成正比关系。这个观点从宏观角度看是正确的,具体到某个系统,良好的架构和设计可以有效减缓这个比率。基于OSGi架构的效率优势在这时候才能体现出来:模块化推动架构师设计出能在一定范围内自治的代码,可以使开发人员只了解当前模块的知识就能高效编码,也有利于代码出现问题时隔断连锁反应。OSGi的依赖描述和约束能力,强制开发人员必须遵循架构约束,这些让开发人员“不自由”的限制,在系统规模变大后会成为开发效率的强大推动力。

图 OSGi对软件复杂度的影响

可以用一个更具体的场景来论述上面的观点,解析OSGi架构如何在开发效率上发挥优势。有经验的架构师会有这样的感受:设计一个具有“自约束能力”的系统架构非常不容易。最常见的情况是设计人员设想得很美好,开发人员在实现时做出来的产品却不是那样。大部分软件公司是通过“开发过程”、“编码规范”、“测试驱动”,甚至“人员熟练度”来保证开发人员实现的代码符合设计人员的意图。这样即使在开发阶段做到符合设计需求,也很难保证日后维护人员能够继续贯彻原有的设计思想;随着开发的时间越来越长,系统最终实现的样子可能和原有的设计产生越来越大的偏差。在软件工程中,将这种现象称为“架构腐化”。架构的“自约束能力”就是指限定不同开发人员在实现功能的时候,实现方式都是一致的,最好只有唯一一条遵循设计意愿的路可走,别的方法无法达到目的。更通俗地说就是,尽可能使程序员不写出烂代码。

举个最浅显的例子,如果有开发人员在Web层中使用DAO直接操作数据库,或者在DAL层直接从HttpSession对象中取上下文信息,这样的代码也许能逃过测试人员的黑盒测试,但是显然是不符合软件开发基本理论的。前者可能因绕过Service层中的事务配置而出现数据安全问题;后者限制了这样的DAO就只能从Web访问,无法重用和进行单元测试。如果项目中出现这样的代码,笔者认为首要责任在架构师,因为架构师没有把各层的依赖分清,如果Web层只依赖Service层的JAR包,那么程序员就无法访问到DAO,如果DAL层没有依赖Servlet APIJAR包,那么程序员就不可能访问HttpSession对象,这就是一种架构缺乏自约束能力的表现。

大概没有哪个架构师会犯上面例子那样幼稚的错误。但是,实际情况也远比例子中的复杂,甚至有一些问题是Java语言本身的缺陷带来的,例如,依赖了一个JAR包就意味着能够访问这个JAR包中的一切类和资源,因为JAR包中的内容没有PublicPrivateProtected之分,无法限制用户能访问什么、不能访问什么。更复杂的情况是在引入了同一个JAR包的不同版本时怎么办?如果依赖包需要动态变化怎么办?使用OSGi一个很重要的目的就是弥补Java中资源精细划分的缺陷,加强架构的自约束能力。

虽然OSGi起源于精小软件占多数的嵌入式领域,但是在Java SE/EE领域中,对于越庞大的系统,使用OSGi进行模块化拆分就越能发挥出优势。在商业上已经有一些使用OSGi控制软件复杂度增长、延缓架构腐化速度的成功案例,如Eclipse Marketplace,它已经拥有了上千个插件,插件的开发者来自全球各地,技术水平差异很大,插件实现的功能也各不相同,是OSGi让这些插件基本遵循了统一的架构约束,并且一般不会因为某个插件的缺陷影响整个Eclipse的质量。

2问:OSGi能让系统变得更稳定吗?

笔者遇到过许多由OSGi框架引发的问题,例如,最典型的ClassNotFoundException异常、类加载器死锁或者在动态环境下的OutOfMemoryError问题等,这些都是基于OSGi架构开发软件时很常见的。从这一方面看,使用OSGi确实会增加系统不稳定的风险,所以,在开发过程中团队中有一两个深入了解OSGi的成员是必要的。

不过,软件是否稳定不是只看开发阶段可能出现多少异常就能衡量的,软件的“稳定”应是多方面共同作用的结果。除了关注开发阶段是否稳定之外,还要关注是否能积累重用稳定的代码,问题出现时能否隔断连锁反应蔓延,缺陷是否容易修复等。在这些方面,OSGi就可以带来相当多的好处,例如:

OSGi会引导程序员开发出可积累可重用的软件。我们无法要求程序刚开发出来就是完全稳定的,但可以在开发过程中尽可能重用已稳定的代码来提升程序质量。大家知道,写日志可以使用Log4j,做ORM会引入HibernateJava中有许多经过长期实践检验的、被证实为稳定的开源项目,这些开源项目的共同特征是都经过良好的设计,能够很方便地在其他项目中使用。相对而言,在自己开发项目时很多人没有注意到要进行可积累的设计。

一种典型现象是项目中出现一些“万能的包”,通常名字会是XXXCommons.jarXXXUtils.jar等,这些包中存放了在项目中被多次调用的代码,但是这样的包不能叫做可重用包。当这些包越来越大、类越来越多、功能越来越强时,与这个项目的耦合就越紧密,一般也就无法用在其他项目中了。在OSGi环境下,“大杂烩”形式的模块是很难生存的,如果某个模块有非常多的依赖项,那么没有人愿意为了使用其中少量功能去承担这些间接依赖的代价。因此设计者必须把模块设计得粒度合理,精心挑选对外发布的接口和引入的依赖,把每个模块视为一个商业产品来对待,这样才能积累出可重用的模块,也利于提高程序稳定性。

基于OSGi比较容易实现强鲁棒性的系统。普通汽车坏掉一个轮胎就会抛锚,但是飞机在飞行过程中即使坏了其中一个引擎,一般都还能保持正常飞行。对于软件系统来说,如果某一个模块出了问题,能够不波及其他功能的运作,这也是稳定性的一种体现。大多数系统都做不到在某部分出现问题时隔离缺陷带来的连锁反应。试想一下,在自己做过的项目中把Common Logging(或slf4j)的包拿掉,系统能只损失日志功能而其他部分正常运作吗?但是对于基于OSGi架构开发系统,在设计时自然会考虑到模块自治和动态化,当某部分不可用时如何处理是每时每刻都会考虑的问题,如果软件在开发阶段跟随着OSGi的设计原则来进行,自然而然会实现强鲁棒性的系统。

OSGi环境下可以做到动态修复缺陷。许多系统都有停机限制,要求7×24小时运行,对于这类系统,OSGi的动态化能力在出现问题时就非常有用,可以做到不停机地增加或禁止某项功能、更新某个模块,甚至建立一个统一更新的模块仓库,让系统在不中断运行的情况下做到自动更新升级。

前面提出的两个问题可以总结为OSGi是否能提升开发效率和软件质量。OSGi在这两方面的作用与软件设计得是否合理关系非常密切,这时OSGi好比一个针对“设计”这个因素的放大杠杆,配合好的设计它会更加稳定、高效,而遇到坏的设计,反而会带来更多问题。

3问:OSGi能让系统运行得更快吗?

系统引入OSGi的目的可能有很多种,但一般不包括解决性能问题。如果硬要说OSGi对性能有什么好处,大概就是让那些有“系统洁癖”的用户可以组装出为自己定制的系统了。例如GlassFish v3.0服务器是基于OSGi架构的,它由200多个模块构成,如果不需要EJBJMS这类功能,就可以把对应的模块移除掉,以获得一个更精简的服务器,节省一些内存。总体上讲,OSGi框架对系统性能是有一定损耗的,我们从执行和内存两方面来讨论。

首先,OSGi是在Java虚拟机之上实现的,它没有要求虚拟机的支持,完全通过Java代码实现模块化,在执行上不可避免地会有一些损耗。例如,OSGi类加载的层次比普通Java应用要深很多,这意味着需要经过更多次的类加载委派才能找到所需的类。在两个互相依赖的模块间发生调用时,可能会由于类加载器互相锁定而产生死锁;要避免死锁的出现,有时候不得不选用有性能损失的串行化的加载策略。在服务层上,动态性(表现为服务可能随时不可用)决定了应用不能缓存服务对象,必须在每次使用前查找,这种对OSGi服务注册表的频繁访问也会带来一些开销。使用一些具体的OSGi服务,例如使用HTTP Service与直接部署在Web容器中的Servlet相比会由于请求的桥接和转发产生一些性能损耗。

其次,从内存用量来看,OSGi允许不同版本的Package同时存在,这是个优点,但是客观上会占用更多内存。例如,一个库可能需要 ASM 3.0,而同一应用程序使用的另一个库可能需要ASM 2.0,要解决这种问题,通常需要更改代码,而在OSGi中只需要付出一点Java方法区的内存即可解决。不过,如果对OSGi动态性使用不当,可能会因为不正确持有某个过期模块(被更新或卸载的模块)中一个类的实例,导致该类的类加载器无法被回收,进而导致该类加载器下所有类都无法被GC回收掉。

仅从性能角度来说,OSGi确实会让系统性能略微下降,但是这完全在可接受范围之内。使用OSGi开发时应该考虑到性能的影响,但不应当将其作为是否采用OSGi架构的主要决策依据。

4问:OSGi能支撑企业级开发吗?

不管关于“OSGi是否能支撑企业级开发”的讨论结果如何,一个必须正视的事实是OSGi对企业级开发的支撑能力正在迅速增强。从2007OSGi联盟建立企业专家组以来,OSGi的发展方向已经逐渐调整到企业级应用领域。在IBMApacheEclipse基金会等公司和组织推动下,企业级OSGi正在变得越来越成熟。

在企业级OSGi出现之前,企业级开发要么是走Java EE的重量级路线,要么是走SSH的轻量级路线。企业级OSGi被引入后并没有扮演一个“革命者”的角色,没有把Java EESSH中积累的东西推倒重来,OSGi更像是在扮演一个“组织者”的角色,把各种企业级技术变为它的模块和服务,使以前的企业级开发技术在OSGi中依然能够发挥作用。

OSGi企业级规范中定义了JDBCJPAJMXJTAJNDI等各种Java EE技术以及SCASDO这些非Java EE标准的企业级技术在OSGi环境中的应用方式,这些容器级的服务都可以映射为OSGi容器内部的服务来使用。并且到现在,企业级规范定义的内容已经不仅停留在规范文字中,已经有不少专注于OSGi企业级服务实现框架出现(例如Apache Aries)了。

另一方面,OSGiBlueprint容器规范统一了Java大型程序中几乎都会用到的依赖注入(DI)方式,使基于BlueprintOSGi模块可以在不同的DI框架中无缝迁移。这个规范得到ApacheSpringSource等组织的大力支持,目前这些组织已经发布了若干个Blueprint规范的实现容器(例如Apache GeronimoEquinox VirgoVirgo前身就是SpringSource捐献的Spring DM 2.0)。在最近两三年时间里,企业级OSGi成为Java社区技术发展的主要方向之一,其发展局面可以说是如火如荼。

不过,我们在使用企业级OSGi的时候也要意识到它还很年轻,其中很多先进的思想可能是遗留程序根本没有考虑过的,还有不少问题的解决都依赖于设计约束来实现。因此,如果是遗留系统的迁移,或者设计本来就做得不好,那么使用OSGi会遇到不少麻烦。以最常见的数据访问为例,如果以前遗留系统使用了ORM方式访问数据库,而迁移到OSGi时没有把实体类统一抽取到一个模块,那么ORM模块的依赖就很难配置了,这时不得不使用Equinox Buddy甚至DynamicImport-Package这类很不优雅的方式来解决。另一个问题是集群,OSGi拥有支持分布式的远程服务规范,而OSGi的动态性是针对单Java虚拟机实例而言的,因此要在集群环境下保持OSGi的动态性,就必须自己做一些工作才行。

作者周志明,资深Java技术专家,对JavaEE企业级应用开发、OSGiJava虚拟机和工作流等都有深入的研究,并积累了丰富的经验。著有畅销书《深入理解Java虚拟机:JVM高级特性与最佳实践》。现任远光软件股份有限公司平台开发部经理兼平台架构师,先后参与过国家电网、南方电网等多个国家级大型ERP项目的平台架构工作。

作者谢小明,资深Java技术专家,具有丰富的JavaEE企业级应用开发开发经验,对OSGiSpringHibernate等技术和框架有比较深入的研究和认识。现任远光软件股份有限公司平台开发部平台架构师,先后参加与过国家电网、南方电网等多个国家级大型ERP项目的平台架构工作。

本文节选自《深入理解OSGi:Equinox原理、应用与最佳实践》,周志明、谢小明著,由机械工业出版社出版。

分享到:
评论

相关推荐

    OSGI 开发文档中文的

    OSGI使用MANIFEST.MF文件来声明bundle的元数据,包括导入和导出的包。 3. **服务注册与发现**:OSGI中的服务模型允许组件通过服务注册表动态提供和查找服务,实现组件间的通信。理解服务接口和实现,以及如何使用...

    osgi介绍osgi介绍

    通过阅读《OSGi原理与最佳实践》和《OSGI实战》这两本书,可以深入了解OSGi的细节,学习如何在实际项目中有效地使用OSGi,解决上述挑战,并充分利用其优势。这些书籍通常会涵盖OSGi的配置、服务注册与查找、打包规范...

    OSGI 实例eclipse插件开发

    5. `osgi_serviceImpl`:这可能是一个自定义的OSGI服务实现,它定义了服务接口和其实现,可以在OSGI环境中提供和使用。 6. `osgi_service`和`osgi_use`:这两个可能是与OSGI服务相关的模块。`osgi_service`可能包含...

    OSGI 入门资料PDF

    OSGI使用服务注册和发现机制,允许组件之间通信,而无需硬编码依赖关系。 2. OSGI实战: 在实践中,OSGI被广泛用于大型复杂项目,如企业级应用、嵌入式系统和设备。例如,通过OSGI,开发者可以在不重启整个应用的...

    OSGI.NET开放工厂使用示例.zip

    这个“OSGI.NET开放工厂使用示例.zip”文件显然是一个教程或演示,旨在向Java和.NET开发者展示如何在C#环境中应用OSGI的概念,特别是关于“开放工厂”这一特定主题。 在OSGI中,开放工厂(Open Factory)通常指的是...

    OSGI

    而工具的使用则可以加速这一过程,例如使用Equinox或Felix作为OSGI容器,使用Bnd或Bndtools进行bundle的构建和管理。 总的来说,OSGI是一种强大的技术,尤其适合大型企业级应用或需要高度模块化和动态性的场景。...

    OSGI组件编程(osgi.component.programming)

    在本教程中,我们将深入探讨如何使用Eclipse和Equinox实现OSGI程序的开发。 首先,确保你已经安装了Eclipse SDK 3.2 M5版本,这是开发OSGI应用的基础工具。此外,还需要从CVS服务器上获取教程项目。通过Eclipse的...

    OSGI规范中文版

    - **命名空间**:规范还规定了OSGi命名空间的使用规则,只有OSGi规范所允许的包、类、接口和方法可以被使用,以确保不同实现之间的兼容性。 ### 知识产权和许可 OSGi联盟对OSGi规范的知识产权保留了相关权利,但...

    spring osgi相关资源

    四、spring-osgi-1.2.1-with-dependencies.zip 这个文件包含了Spring OSGi的核心库和其依赖,主要包含以下几个部分: 1. spring-osgi-core:提供OSGi环境下的Spring核心功能,如Bean管理、事件发布等。 2. spring-...

    OSGi入门教程(OSGi Introduce)

    3. **企业级应用**:IBM WebSphere、BEA microServices、Apache Struts、Spring等均使用OSGi,提高了应用的灵活性和可维护性。 OSGi的组成部分包括: 1. **运行环境**:基础的执行环境,支持OSGi服务的运行。 2. *...

    Enterprise OSGI in action

    书中分成三个部分:首先介绍了为何现在使用OSGi对企业编程很重要,然后带领读者了解如何构建更好的企业OSGi应用,最后探讨如何将企业OSGi与其他系统集成。 在模块化编程方面,OSGi提供了一套规则来强化Java的模块化...

    OSGI + Webservice 例子

    7. **测试与调试**:了解如何对OSGI环境中的Web服务进行单元测试和集成测试,以及如何使用OSGI的调试工具进行问题定位。 通过这个例子,新手不仅可以掌握OSGI的基本概念和操作,还能了解到如何将OSGI模块与Web服务...

    OSGI原理与最佳实践

    资源名称:OSGI原理与最佳实践内容简介:国内第一本OSGi图书OSGi国内推广者林昊多年经验的结晶涵盖OSGi从入门到深入的知识体系引领OSGi国内研究和普及本书基于作者多年使用OSGi的经验而编写,涵盖了OSGi从入门到深入...

    osgi,林昊写的osgi实战和进阶

    OSGI(Open Services Gateway Initiative)是一种Java模块化系统,它允许开发者将应用程序分解为一系列可独立部署、更新和交互的服务。林昊所著的《OSGI实战》与《OSGI进阶》是深入理解OSGI技术的重要参考资料,适合...

    osgi学习笔记(一)

    本文将深入探讨OSGi的基本概念、架构以及如何使用它来构建可扩展和灵活的Java应用程序。 首先,我们需要了解OSGi的核心概念——模块化。在OSGi中,每个Java应用程序被划分为独立的模块,称为“bundle”。这些bundle...

    osgi重要文档--osgi核心规范文档,osgi服务文档,osgi-最佳原理与实践(王昊编著,共79页)

    这个压缩包包含了关于OSGI的重要文档,分别是“OSGi R4核心规范文档”、“OSGi服务文档”以及“OSGi-最佳原理与实践”(王昊编著)。下面将详细介绍这些文档所涵盖的关键知识点。 首先,"OSGi R4核心规范文档"是...

    《OSGi实战》完整中文版

    《 OSGi实战》是学习OSGi的全面指导,利用与架构和开发人员相关...《OSGi实战》面向OSGi规范的使用者,系统、全面、深入地阐述OSGi的重要特性及其使用方法,还介绍了某些技术的低层实现细节,引领读者畅游OSGi的世界。

    利用R-OSGi实现分布式OSGi应用

    利用R-OSGi实现分布式OSGi应用 本文通过介绍传统 OSGi 应用程序及 R-OSGi 的实现方式入手,阐述了 R-OSGi 对于 OSGi 规范的实现方式。...最后,探讨了 R-OSGi 的目前使用情况以及整个分布式 OSGi 应用的发展前景。

    OSGI入门和例子

    5. **依赖管理**:OSGI使用MANIFEST.MF文件来声明bundle的依赖关系,这样在运行时可以自动解决这些依赖,避免了类加载的困扰。 6. **动态性**:OSGI的一大优势是其动态性,允许在运行时添加、删除或更新bundle,...

Global site tag (gtag.js) - Google Analytics