绑定和应用上下文
在osgi中bundle是部署和模块化的单位(见osgi服务平台核心规范的3.2)。一个绑定在osgi运行时处于三个固定状态之一:已安装、已解析和激活。绑定可以向osgi服务注册输出服务,并且以此使输出的服务可以被其他绑定发现和使用。绑定也可以导出为java包,供其他绑定导入该服务的类型。
spring中模块的主要单位是应用上下文,它包括一些bean(被spring应用上下文管理的对象)。应用上下文可以通过配置继承,这样子上下文可以访问父上下文中定义的bean,但是反之不可以。spring概念中的导出器和工厂bean用于向应用上下文以外的客户程序导出bean的引用。
osgi的绑定和spring的应用上下文存在自然的对应联系。使用spring-dm,一个激活状态的绑定可以包含一个spring应用上下文,用于在绑定中对bean实例化、配置、装配和包装。这些bean中可选择其中的一些导出为osgi服务,因此可被其他绑定访问,绑定中bean的引用也可透明的被注入到osgi服务。
spring动态模块扩展器绑定
spring-dm提供了一个osgi绑定:
org.springframework.osgi.bundle.extender
该绑定用于为编写的应用绑定实例化spring应用上下文。功能类似于ContextLoaderListener对spring的web应用。一旦这个扩展器绑定被安装并且已启动,它将查找所有存在的spring提供的已处激活状态的绑定,并且为之创建应用上下文。另外,它监听绑定的启动事件并自动为任何spring提供的绑定创建应用上下文并随之启动。
扩展器模式:
在osgi应用中的一个普遍的模式是扩展器,它允许其他绑定在特定领域内扩展功能。
应用上下文的创建
扩展器绑定异步地创建应用上下文。这确保了启动osgi服务平台是快速的而且和绑定内部依赖的服务中间不会在启动时发生死锁。一个spring提供的绑定可以在应用上下文启动前转换到已启动状态。
如果应用上下文因任何原因创建失败则日志将记录失败原因。这个绑定将停在已启动状态。在这种情况下服务不会从应用上下文导出注册。
强制服务的依赖
如果一个应用上下文声明强制依赖某个特定的osgi服务,则创建该应用上下文时将被阻塞,直到所有强制依赖确保匹配和可用。一个服务在osgi环境的任何时刻,上述行为只能确保所有强制服务可用才会开始创建应用上下文。有时一个或者多个服务可能在应用上下文创建过程中变为不可用,《服务注册》部分描述当强制服务的引用变为不可用时发生何种情况。实践中,大多数使用spring-dm服务的企业应用,它包含的可用服务和绑定将会在平台及其安装的绑定都启动后进入稳定状态。比如说,等待强制依赖仅仅确保需要绑定a和b,而绑定a依赖绑定b导出的服务,这时它们是以任意顺序启动。
超时用于等待强制依赖满足要求。超时默认设置为5分钟,也可以自行设置timeout值。详见《绑定格式和清单头》部分。
应用上下文因为所有强制服务没有立即可用而创建失败,为使之启动,可以修改应用上下文创建的配置。当设置为不等待依赖,一个未满足强制依赖的绑定将停止,并将该绑定置为已解析状态。
应用上下文服务的发布
应用上下文为绑定创建完成后,通过osgi服务注册将自动导出该应用上下文对象为可用的服务。该上下文通过:
org.springframework.context.ApplicationContext
类型接口发布。被发布的服务有一个服务属性名为:
org.springframework.context.service.name
它的值用于设置在应用上下文中的该绑定的符号名称。这可防止服务的应用上下文作为使用指定绑定清单的服务被发布。详见《绑定格式和清单头》部分。
注意:应用上下文发布为服务,主要是为了方便测试、管理和操作。不鼓励在运行时访问上下文对象getBean()或者类似的操作。供其他应用上下文访问的更好方式是在上下文定义该bean导出为osgi服务,然后导入该服务在上下文中的引用给需要访问的服务。这种通过服务注册的方式确保一个bean只看到兼容版本服务类型的服务,而且符合osgi平台机制。
绑定的生命周期
osgi是一个动态平台:在它运行的任意时间都可安装、启动、更新、停止和卸载绑定。
当一个激活的绑定被停止,在它生存期间任何为之导出的服务自动注销,而且该绑定回到已解析状态。一个已经停止的绑定应释放所有它申请的资源资源并中止所有线程。已停止的绑定导出过的包对其他绑定继续可用。
处于已解析状态的绑定可以卸载:已卸载绑定导出的包对导入他们的绑定继续可用(但对新安装的绑定不可用)。
处于已解析状态的绑定也可更新。更新过程从同一绑定的一个版本迁移到另一个版本。
当然,已解析绑定可以启动,将转换到激活状态。
osgi的PackageAdmin refreshPackages操作刷新整个osgi框架或者指定的已安装绑定子集的包。刷新期间,受到影响绑定中的应用上下文将被停止和重启。refreshPackages操作后,旧版本绑定导出的包将不可用。详细信息见osgi规范。
当停止一个spring提供的绑定,为之创建的应用上下文将自动销毁。素有该绑定导出的服务将注销(从服务注册中删除),而且正常的应用上下文销毁和生命周期规则将进行(应用上下文回调bean的销毁方法)。
如果spring提供的绑定已经被停止,而稍后重启,将为之创建新的应用上下文。
资源的抽象
spring框架定义了资源的抽象,用于为应用上下文加载资源。所有资源加载通过与该应用上下文相关的:
org.springframework.core.io.ResourceLoader
bean也可通过编程使用它加载资源。资源路径通过显式的前缀–比如classpath:–在所有应用上下文类型(比如web应用上下文和基于类的应用上下文)中被一致看待。而相对资源路径在不同类型的上下文解释是不同的。这易于在最终部署环境外的集成测试。
osgi 4.0.x规范定义了三种不同的加载资源的空间。spring-dm支持所有osgi规范中提及的应用上下文和前缀:
| osgi搜索方式 | 前缀 | 解释 |
| 类空间 | classpath: | 搜索绑定的类加载器 |
| 类空间 | classpath*: | 搜索绑定的类加载器 |
| jar空间 | osgibundlejar: | 只搜索绑定的jar |
| 绑定空间 | osgibundle: | 搜索绑定的jar和它附加的片段 |
可查阅osgi规范4.3.12中有关上述内容的深入解释。
注意:如果未指定前缀,将使用绑定空间osgibundle。
注意:根据osgi动态属性,绑定的类路径可在其生存期间改变。(比如当使用动态导入)。当基于运行环境或者目标平台的进行模式匹配时,可能出现返回不同的类路径资源。
所有spring资源规则中的前缀比如file:和http:也被支持,可作为模式匹配的通配符。使用这些前缀加载的资源可来自任何位置,并不限制是定义在资源加载中的绑定或者它附加的片段。
osgi平台可定义属于自己的统一的前缀来访问绑定的内容。比如,equinox定义bundlesource:和bundlentry:前缀。这些特定平台定义的前缀也可用于spring-dm,当然,代价是只能使用在特定的osgi实现。
访问绑定上下文
总体上说当使用spring-dm不需要依赖osgi API。如果确实需要在绑定中访问osgi的BundleContext对象,spring-dm有简化的做法。
由spring扩展器创建的osgi应用上下文,将自动的包含一个BundleContext类型的bean,名称为bundleContext。可以通过by-name或者by-type注入这个引用到应用上下文任意的bean中。另外,spring-dm定义了接口:
org.springframework.osgi.context.BundleContextAware
任何实现该接口的bean将被spring配置注入绑定上下文的引用。如果希望使用这个机制到绑定上,记住导入以下包到该绑定的清单:
org.springframework.osgi.context
应用上下文的销毁
应用上下文捆绑在运行中的绑定上。因此如果让绑定关闭,应用上下文也将销毁,所有导出的服务将注销,并去除所有导入的服务。
注意,无论是绑定被单独关闭,或者作为更大的事件的一部分,比如关闭整个osgi平台,当这种情况或者当扩展器绑定被关闭时,被管理的应用上下文将按照基于服务间依赖关系的方式被关闭。下节有更详细描述。
停止扩展器绑定
如果停止扩展器绑定,则所有该扩展器创建的应用上下文将销毁。应用上下文按以下次序关闭:
- 没有导出任何服务的应用上下文,或者导出的服务当前未被引用,关闭按照绑定的id降序。(最近安装的绑定,它的应用上下文最先关闭)。
- 关闭步骤(1)中释放引用的应用上下文,然后,重复步骤(1)。
- 如果不再有活动的应用上下文,将结束。如果还有活动的应用上下文,一定是有循环依赖引用。打破循环由每个上下文中导出的最高级别服务决定:绑定中最低级别的服务被关闭。重复步骤(1)。
这篇文章上的评论的 RSS feed TrackBack URI