领先一步
VMware 提供培训和认证,助您飞速进步。
了解更多欢迎来到我的博客!这是我的第一篇博文...有史以来第一篇。我一直努力克制写博客的冲动,但既然这么多人鼓励我写写我在 i21 的工作,我决定试一试。此外,还有一个原因,就是 Spring-OSGi 昨晚(东欧时间)发布了第一个 版本。
我从去年八月就开始参与 Spring-OSGi 项目了,这段经历相当不错。这是我做过的最具挑战性的项目之一,我很高兴它能向公众发布,哪怕只是一个里程碑版本。非常感谢所有参与其中的人促成了这一切,特别是我的 团队 伙伴——Adrian、Andy 和 Hal!
在这篇博文中,我想让您对 Spring 1.0 M1 目前提供的内容有个大致了解;我将跳过介绍 OSGi,因为互联网上有很多优秀的资料(见底部的链接)。
Spring-OSGi 背后的基本思想是让在 OSGi 环境中构建/编写/部署 Spring 应用程序变得容易。也就是说,让 Spring 提供的全面的基于 POJO 的编程模型(IoC、AOP、服务抽象)在注重版本控制和模块化的动态执行环境中透明地工作。
采用 OSGi 时最大的挑战之一是处理其动态特性。服务(它们是简单的对象实例)可能会出现或消失,您的应用程序必须处理这种情况。解决方案并不直接,因情况而异,并且需要像异常处理和事务处理一样应用范围内的考虑。上述模块化强制执行的类加载限制,结合 AOP,可能会导致很多麻烦,并迫使开发人员进行变通,从而丢弃 OSGi 带来的好处。这些只是我们在 Spring-OSGi 中正在解决的一些少数问题示例,最终应该能够让采用 OSGi 的过程更加顺畅。
让我们看看您在 1.0 M1 中会发现的一些功能
OSGi 基于 bundles(捆绑包),它们不过是带有特定清单条目的 Jar 文件。它们是模块,是导出和导入类包和/或服务的单元。一个应用程序可以由一个或多个捆绑包组成。Spring-OSGi 提供了一个基于捆绑包及其生命周期的应用上下文,让您可以访问应用程序所在的 OSGi 上下文、一个 OSGi 自定义 作用域以及一个 额外的 Aware 接口。与其他同类接口一样,该接口提供了进行依赖查找的能力,但在使用之前您应该三思,因为 OSGi 服务依赖注入已得到充分支持。
在 OSGi 中,类加载已与以前不同了——例如,classpath 有了不同的含义,因为它可以由多个捆绑包组装而成(而这些捆绑包又可以在多个 classpath 中使用)。因此,getClass().getResource() 可能会产生不同的结果,因为运行环境已经发生了很大的变化。下面是一个寻找类时可能得到的结果示例:
Equinox: bundleentry://5/my/package/MyClass.class(也可以是 bundleresource://) Knopflerfish: bundle://13/my/package/MyClass.class Felix: bundle://18.0/0/my/package/MyClass.class
依赖 URL scheme(方案)是不可移植的,因此 Spring OSGi 最先做的事情之一就是通过简单而有效的 Resource 接口封装低级访问,这样无论您使用哪种 OSGi 实现,都可以找到您的文件。此外,模式风格的查找(如 myFolder/*)也是可能的(实际上我们使用 /META-INF/spring/* 来检测“spring powered”捆绑包)。
假设您有以下应用上下文
<!-- service layer-->
<bean id="myService" class="ServiceClass">
<property name="dao" ref="dao"/>
</bean>
<!-- dao layer -->
<bean id="dao" class="poorPerformerDAO">
<property name="dataSource" ref="someDataSource"/>
</bean>
大多数应用程序都有多个层,这些层非常适合作为 OSGi 捆绑包,因为您可以简单地将 DAO 类放在一个捆绑包(dao 捆绑包)中,将服务层放在另一个捆绑包(service 捆绑包)中,这样当 DAO 实现更新时(例如上面的 poorPerformerDAO 被 excellentPerformerDAO 替换),或者部署不同版本的应用程序时,无需重新启动应用程序:这是选择 OSGi 的最佳理由之一!
然而,要利用 OSGi 的能力,对象必须成为服务——也就是说,它们必须在“消费”之前注册到 OSGi 平台,而消费者(客户端)必须查找它们。这是一种类似于 SOA 的方法,可以避免模块之间的紧密耦合,因此当一个捆绑包关闭时,由它发布的服务就会消失。这意味着首先必须使用 OSGi API 进行注册和查找,而且还必须处理服务可能出现或消失带来的故障。
Spring-OSGi 在这方面提供了很大的帮助,它允许几乎任何类型的对象在您的应用程序中导出和导入,而无需任何代码更改。
服务捆绑包
<!-- service layer-->
<bean id="myService" class="ServiceClass">
<property name="dao>
<osgi:reference interface="daoInterface"/>
</property>
</bean></code>
Dao 捆绑包
<!-- dao layer -->
<bean id="dao" class="goodPerformerDAO">
<property name="dataSource" ref="someDataSource"/>
</bean>
<osgi:service ref="dao"/>
使用 Spring-OSGi 适应 OSGi 环境,需要添加两行配置
<li><span style="font-family:courier"><osgi:service ..></span> to export an existing bean as an OSGi service</li>
显然,对于 dataSource 依赖也可以这样做——将其外部化到一个 OSGi 捆绑包中,然后只需将普通的 ref 替换为 osgi:reference。无需处理新的 API,无需处理 try/catch/finally 的异常,特别是内置的查找行为。可以配置 Spring-OSGi,以便只有在找到实现 daoInterface 的服务时才启动应用上下文——也就是说,可以满足 dao 依赖。此外,在运行时,如果服务消失,Spring-OSGi 将根据您的配置(重试次数和超时)自动寻找新的实现:如果在拥有该 bean 的捆绑包更新时(例如将 goodPerformerDAO 升级到 excellentPerformerDAO)恰好调用了 'dao' bean 上的方法,您不会收到一个令人讨厌、显然无法解释的异常,而是会感受到一个因查找新服务而引起的微不足道的延迟。一如既往,此行为是完全可配置的。
在某种程度上,导出器/导入器功能类似于 Spring remoting,但主要的区别在于它不涉及远程调用——所有内容都在同一个 JVM 中运行,并且完全不涉及序列化。
测试很重要(甚至至关重要),特别是在将应用程序迁移到新环境时,因为许多被认为是理所当然的事情可能会失败:我们在开发初期就亲身体验了这一点。这是一个大问题,因为谈到 OSGi 时,测试绝非易事或自动化,因为执行环境(如果您愿意,可以称之为 OSGi 平台或容器)必须启动(没有标准化 API)并进行设置(安装您的测试依赖的捆绑包)。然而,棘手的部分在于测试本身必须 OSGi 化——放置在一个声明依赖关系的清单旁边,成为一个必须安装并启动到 OSGi 平台中的捆绑包。
认识 AbstractOsgiTests 及 其伙伴
public class SimpleIntegrationTests extends AbstractConfigurableBundleCreatorTests
{
public void testInstalledBundles() {
// get access to the OSGi bundle context
Bundle[] bundles = getBundleContext().getBundles();
getBundleContext().installBundle(someBundleLocation);
assertEquals(bundles.length()+1, getBundleContext().getBundles().length());
}
// specify the bundles to install
protected String[] getBundles() {
return new String[] {
"org.springframework.osgi, commons-collections.osgi, 3.2-SNAPSHOT",
"org.springframework.osgi, org.springframework.osgi.test.simple.service,1.0-SNAPSHOT"};
}
}
AbstractOsgiTests 构建在 JUnit 之上,因此您可以直接从 IDE 中编写和运行 OSGi 集成测试。整个设置由测试基础设施处理,您无需操心:无需为测试编写 MANIFEST.MF 文件,无需进行任何打包或部署——一切都自动处理。而且它速度很快,非常快!实际上,只有不到 10% 的启动时间花在 Spring-OSGi 代码内部——其余时间由 OSGi 平台本身使用。我们的大多数集成测试都在 1-3 秒内完全执行。Equinox、Knopflerfish 和 Felix 都支持。
嗯,我觉得第一篇博文就写到这里吧... 今后的博文我会写更多关于 Spring-OSGi 功能的内容。希望我已引起您的兴趣,让您想试试 1.0 M1(请注意这是第一个里程碑版本,还有一些“不足之处”)。
感谢阅读!Costin
OSGi Alliance 提供了一些不错的 入门 和 白皮书 维基百科 EclipseCon OSGi 专题 Spring-OSGi 规范 Javapolis 2006 关于 Spring-OSGi 的 演讲(由本人主讲) 最后,但同样重要的是,老朋友 Google。