那么Spring-OSGi到底是怎么回事呢?

工程 | Costin Leau | 2007年4月5日 | ...

欢迎来到我的博客!这是我的第一篇博文……有史以来。我设法抵制了写博客的冲动,但由于很多人鼓励我写一些我在i21的工作内容,我决定尝试一下。还有就是Spring-OSGi在昨天晚上(EET时区)发布了第一个版本

从去年8月起我就参与了Spring-OSGi项目,这确实是一段有趣的旅程。这是我参与过的最具挑战性的项目之一,我很高兴能够将其(即使只是一个里程碑版本)发布给公众。非常感谢所有参与其中的人,特别是我的团队成员——Adrian、Andy和Hal!

在本篇博文中,我想让您了解一下Spring 1.0 M1目前提供了哪些功能;我将跳过OSGi的介绍,因为互联网上有大量优秀的资料(请参见底部的链接)。

Spring-OSGi背后的基本思想是简化在OSGi环境中构建/编写/部署Spring应用程序的过程。也就是说,让Spring提供的全面的基于POJO的编程模型(IoC、AOP、服务抽象)能够在以版本控制和模块化为中心的动态执行环境中透明地工作。

采用OSGi时最大的挑战之一是处理其动态特性。服务(它们只是简单的对象实例)会不断出现和消失,您的应用程序必须能够处理这种情况。解决方案并不简单,具体情况需要具体分析,并且需要像异常处理和事务一样具有应用程序范围的作用域。模块化强制实施的类加载限制,加上AOP,可能会造成很多麻烦,并迫使开发人员创建一些hack,从而放弃了OSGi提供的优势。这些只是我们在Spring-OSGi中解决的一些问题,最终,应该可以实现OSGi的平滑过渡路径。

让我们看看1.0 M1中的一些功能。

  1. OSGi应用程序上下文

OSGi基于bundle,bundle只不过是带有一些专用清单条目(manifest entries)的jar文件。它们是模块,导出和导入类包和/或服务的单元。一个应用程序可以由一个或多个bundle组成。Spring-OSGi提供了一个应用程序上下文,该上下文构建在bundle及其生命周期之上,使您能够访问应用程序所在的OSGi上下文,一个OSGi自定义作用域以及一个额外Aware接口。与其他同类接口一样,该接口提供了执行依赖项查找的功能,在使用该功能之前,您应该仔细考虑,因为OSGi服务依赖项注入得到了完全支持。

  1. 资源抽象

OSGi中的类加载机制与以往不同——例如,类路径的含义有所不同,因为它可以由多个bundle组成(而这些bundle又可以用于多个类路径)。因此,getClass().getResource()的结果可能会有所不同,因为运行环境发生了很大变化。以下是一个查找类时可能出现的结果示例。

Equinoxbundleentry://5/my/package/MyClass.class(也可以是bundleresource://Knopflerfishbundle://13/my/package/MyClass.class Felixbundle://18.0/0/my/package/MyClass.class

依赖于URL方案不具有可移植性,因此Spring OSGi首先要做的事情之一就是通过简单而有效的Resource接口封装底层访问,因此无论您使用什么OSGi实现,都可以找到您的文件。此外,还支持诸如myFolder/*之类的模式样式查找(实际上,我们使用/META-INF/spring/*来检测“由Spring驱动的”bundle)。

  1. 动态服务支持

假设您有以下应用程序上下文。


<!-- 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 bundle,因为可以简单地将DAO类放在一个bundle(dao bundle)中,将服务层放在另一个bundle(service bundle)中,因此当DAO实现更新时(例如,上面的poorPerformerDAOexcellentPerformerDAO替换)或应用程序的不同版本被部署时,无需重新启动应用程序:这是选择OSGi的最佳理由之一!

但是,要利用OSGi的功能,对象必须成为服务——也就是说,它们必须在“使用”之前向OSGi平台注册,而使用者(客户端)必须查找它们。这是一种类似于SOA的方法,它避免了模块之间的紧耦合,因此当一个bundle关闭时,它发布的服务就会消失。这意味着首先必须使用OSGi API进行注册和查找,但同时也必须处理失败,因为服务可能会出现和消失。

Spring-OSGi在这方面提供了极大的帮助,它允许您在应用程序中导出和导入任何类型的对象,而无需进行任何代码更改。

服务Bundle


<!-- service layer-->
<bean id="myService" class="ServiceClass">
    <property name="dao>
       <osgi:reference interface="daoInterface"/>
    </property>
</bean></code>

Dao Bundle


<!-- dao layer -->
<bean id="dao" class="goodPerformerDAO">
    <property name="dataSource" ref="someDataSource"/>
</bean>

<osgi:service ref="dao"/>

使用Spring-OSGi来适应OSGI环境,需要添加两行配置。

  1. 指示框架查找什么OSGi服务。
  2. <li><span style="font-family:courier"><osgi:service ..></span> to export an existing bean as an OSGi service</li>
    

显然,对于dataSource依赖项也可以执行相同的操作——将其外部化到OSGi bundle中,只需将普通的ref替换为osgi:reference即可。无需处理新的API,无需为try/catch/finally编写异常处理,并且内置了查找行为。可以指示Spring-OSGi,除非找到实现了daoInterface的服务,否则应用程序上下文不会启动——也就是说,可以满足dao依赖项。此外,如果在运行时服务消失,Spring-OSGi将根据您的配置(重试次数和超时时间)自动查找新的实现:如果恰好在拥有bundle更新时(例如,将goodPerformerDAO升级到excellentPerformerDAO)调用“dao”bean上的方法,则不会出现令人讨厌的、显然无法解释的异常,而是会出现由新的服务查找导致的微不可查的延迟。与往常一样,行为是完全可配置的。

在某种程度上,导出器/导入器功能类似于Spring远程调用,但最大的区别在于不涉及远程调用——所有内容都在同一个VM中运行,并且根本不涉及序列化。

  1. 集成测试

测试非常重要(甚至至关重要),尤其是在将应用程序迁移到新环境时,因为许多理所当然的事情可能会失败:我们在开发的早期就亲身体验了这一点。这是一个很大的问题,因为当涉及到OSGi时,测试一点也不容易或自动化,因为必须启动执行环境(OSGi平台或容器,如果您愿意的话)并进行设置(安装测试依赖的bundle)。但是,棘手的是,测试本身也必须是OSGified——与声明依赖项的清单一起放置在一个bundle中,该bundle必须安装并启动到OSGi平台中。

了解AbstractOsgiTests & co


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秒内完成。

好吧,我认为对于第一篇博文来说,这些内容已经足够了……我将在以后的博文中详细介绍Spring-OSGi的功能。我希望我已经激发了您足够的兴趣,让您尝试一下1.0 M1(请注意,这是第一个里程碑版本,它有一些“粗糙的边缘”)。

感谢您的阅读!Costin

OSGi联盟提供了一些不错的介绍白皮书维基百科 EclipseCon OSGi 主题 Spring-OSGi 规范 Javapolis 2006 演示文稿(由本人提供)最后,但并非最不重要的一点是,老式的Google

获取Spring时事通讯

与Spring时事通讯保持联系

订阅

领先一步

VMware 提供培训和认证,助您快速提升技能。

了解更多

获取支持

Tanzu Spring 通过一个简单的订阅提供 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件。

了解更多

即将举行的活动

查看 Spring 社区所有即将举行的活动。

查看全部