翻译:shuyaji 2006-11-17
原文地址: http://www.springframework.org/osgi/specification
1.0 简介
Spring框架是一个领先的full-stack Java/JEE应用框架。它提供一个轻量级的容器,依赖注入、aop、可插接的服务抽取,这些使得非侵入式的编程模型成为可能。OSGi提供了一个动态应用程序的执行环境,在这个环境中组件(bundles)可以在运行中被安装、更新、删除。它同时也可以很好地支持模块化及版本化。
Spring’OSGi的目标是使得写基于Spring的应用程序尽可能的容易,这些应用可以部署到OSGi的执行环境中,并可有效利用OSGi框架所提供的服务。通过在易用、强大的Spring框架上构建应用程序,Spring对OSGi的支持也使得开发这样的基于OSGi的应用更加简单、更加高效。
- 更好的分离应用逻辑与模块;
- 同时部署一个模块的多个版本的能力;
- 动态查找、使用系统其它模块提供的服务的能力;
- 在运行时系统中动态部署、升级、卸载模块的能力;
- 使用Spring框架在模块之间实例化、配置,集成,装饰组件;
- 让企业应用开发者使用简单、熟悉的编程模型开发OSGi平台的功能。
我们相信OSGi与Spring的结合为构建企业应用提供了最全面的可用的模型。
Spring’s OSGi的目标并不是提供一个通用的模型以支持任意的基于OSGi的应用程序开发,但是某些OSGi的开发者肯定能够发现Spring模型吸引人之处,并采纳它。目前已经存在的OSGi的bundles以及它们所export的任何服务都可以轻松的集成到使用SpringOSGi支撑的应用中,就象是Spring已经存在的配置项。
Spring OSGi定位于OSGi R4及以上版本,JDK1.3及以上版本。
这个规范假设读者已经具有一定的Spring及OSGi的知识。参见介绍白皮书“OSGi for Spring developers”以及“Spring for OSGi developers”。注意:这些白皮书现在还不存在,还处于书写阶段,吼吼吼。
2.0 Bundles and Application Contexts
OSGi中的开发单元(以及模块单元)是bundle。OSGi中所说的bundle有三种稳定状态:installed,resolved,active。Bundles可以导出(export)服务,其它的bundles可以查找并使用这个服务。
在Spring中主要的模块化单元是一个application context,它包含很多个beans(由Spring应用环境所管理的对象)。Application contexts可以分级配置,这样一个子application context可以看到定义在其上级的beans,但是反之则不行。Spring的exporters及factory beans的概念用于导出引用给application context外部的客户端的beans,以及注入引用到定义在一个application context外部的服务。
OSGi的bundle与Spring的application context有着本质的联系:一个激活的bundle可以包含一个Spring的application context,负责在bundle中实例化、配置、组装以及装饰对象(beans)。其中一些beans可以被导出(export)为OSGi服务以供其它bundles使用,在bundle中的beans也可以被轻松的注入OSGi服务引用。
2.1 在Bundle中创建Application Context
一个Application context可以使用一个或多个定义了beans的XML配置文件来配置。(严格地说,一个application context对于配置的形式并不可知,但是XML是最常用的形式)。包含配置信息的XML文档放置于bundle中的META-INF/spring文件夹。缺省情况下,Spring将使用在这个文件夹中的所有以“.xml”为扩展名的文档,作为application context的配置定义。
缺省设置可以在Spring-Context的manifest header中重写。Header的值是由逗号分隔的资源路径及指令列表。
Spring-Context ::= context ( ’,’ context ) *
> context ::= path ( ’;’ path ) * (’;’directive) *
每一个路径都被当作在bundle中定义的资源路径处理,例如:
Spring-Context: config/application-context.xml,config/security.xml
当带有Spring-Context manifest入口文件或者位于META-INF/spring文件夹中的资源的bundle被激活时,Spring将自动创建application context。为了达到这一点,你必须首先安装(install)并启动(start)在你的OSGi运行时中的org.springframework.osgi.extender bundle。
当一个application context被首先创建后,它就判断所配置的OSGi服务引用,看是否有任何服务引用指定了cardinality(例如指定1..1或者1..n)。直到所有必须的服务都可用之后,这个context的初始化才结束。wait-for-dependencies指令可以在Spring-Conext头中设置为false从而改变这种行为。当wait-for-dependencies设置为false时,如果application context在被激活时其所必须的服务还不可用,创建application context将失败。
清单头条目(The manifest header entry):
Spring-Context: *;wait-for-dependencies:=false
表示所有在META-INF/spring中的xml文件都应该被配置,并且如果context所必须的服务不是立即可用,context的创建将会失败。
A header entry:
Spring-Context: config/application-context.xml;wait-for-dependencies:=false
表示使用config/application-context.xml配置文件来配置application context,并且如果其所必须的服务没有立即可用,context的创建将会失败。
Application context作为org.springframework.context.ApplicationContext的一个实例被自动发布为一个OSGi服务。此外,org.springframework.context.service.name用于设置驻留了application context的bundle的标识名称。通过在Spring-Context manifest entry中指定“publish-context:=false”可以禁止发布context为一个服务。
注意:application context被发布为一个服务使得测试和管理变得容易。获取一个指向在其它application context中定义的bean的首选方式是使用<osgi:reference> 和 <osgi:service>元素(相对于在application context服务中调用getBean()方法)。原因就在于通过使用<osgi:reference> 和 <osgi:service>组成服务,OSGi的基础架构将保证一个bean只能看到类的版本与之相兼容的服务,反之如果在注册表中查找一个application context,然后调用getBean(…)返回一个对象,然后类兼容性的唯一保证就是ApplicationContext类自身是兼容的。很明显在一个存在同时部署了多个版本的bundle的系统中,这种保证是不够健壮的。
2.2 Spring资源抽取
Spring在application context中使用Spring ResourceLoader加载资源。相关资源路径由application context以一种与application context类型相符的方式(例如基于context的class path,或基于context的web-app)解释。对OSGi应用来说,相关资源路径作为从bundle classpath中加载的资源解释。如果资源路径以“bundle:”前缀开头,那么只以给定的资源搜索bundle自己及其附加的fragments。
2.3 BundleContextAware
Spring鼓励基于不依赖于任何环境的简单对象开发应用。但是,如果一个Spring bean由于某种原因的确需要访问它的BundleContext,那么这个bean可以实现org.springframework.osgi.context.BundleContextAware接口。实现这个接口的Bean当在application context中实例化时将会被注入BundleContext。
2.4 使用Context ClassLoader
目前存在很多很有用的第三方包及应用,它们对OSGi一无所知,并且依靠线程环境ClassLoader动态加载类。OSGi没有定义context类加载器在任何时间点将是什么(OSGi does not define what the context ClassLoader will be at any point in time.)。这个现实与OSGi的非分级的类加载机制相符,意味着这些包将不能找到它们所需要的类和资源。
举一个简单的例子,一个应用被打包到bundle A中,使用bundle H所导出的Hibernate的类创建了一个Hibernate SessionFactory。这个SessionFactory将会需要加载定义在bundle A中的应用的类及资源,但是对于它来说,在OSGi环境中,bundle A是不可见的。为解决这个问题,Context ClassLoader对于任何从bundle A发起调用到bundle H的线程来说必须被设置为A的bundle ClassLoader。
Spring-OSGi保证了当激活一个bundle时,context ClassLoader总是被设置为能够访问被激活的bundle的资源。这样在bean实例化及配置阶段发起的对包的调用总是产生于一个合适的context ClassLoader的上下文环境中。
请求Spring管理context ClassLoader调用OSGi服务也是可能的,以及对作为OSGi服务而暴露的beans的调用。想了解更多的细节请参考第三部分。
2.4.1 Other contexual access
Spring bean能够实现BundleContextAware接口以方便被注入它所在的bundle的BundleContext引用。在bundle被激活以及其它调用某个被当作Spring bean访问的OSGi服务时,Spring也会通过一个ThreadLocal变量来提供对“当前”bundle的BundleContext的访问,这个变量可通过LocalBundleContext.getContext获取。
2.5 Web应用支持
Spring使用ServletContextListener,org.springframework.web.context.ContextLoaderListener来自动的为web应用创建WebApplicationContext。OSGi可用的WebApplicationContext,org.springframework.osgi.context.support.WebApplicationContext版本提供用来在OSGi中运行web应用。要使用这种支持,需要在你的web.xml文件中设置监听器声明的contextClass参数为“org.springframework.osgi.context.support.WebApplicationContext”。
3.0 OSGi平台服务和动态本质
OSGi是一个动态的平台:bundles可能在框架运行期的任意时刻被安装、启动、更新、停止以及卸载。在本章我们将从application context及其发布和访问的服务的角度来揭示这意味着什么。
当一个激活的bundle停止时,在它的生命周期中它所导出的任何服务也将被自动反注册,并且bundle返回到resolved状态。停止的bundle会释放所有它所获取的资源,终止所有的线程。停止的bundle所导出的Packages仍然对其它bundles可用。
处于resolved状态的bundle可以被卸载:被卸载的bundle所导出的packages也仍然对其它导入它们的bundles可用(除了新安装的