OSGi 基本原理

定义

OSGi(Open Service Gateway Initiative)技术是面向Java的动态模型系统。

这个框架实现了一个优雅、完整和动态地组价模型。应用程序(称为bundle)无序重新引导可以被远程安装、启动、升级和卸载。

OSGi服务平台提供在多种网络设备上无需重启的动态改变构造的功能。

为了最小化耦合度和促使这些耦合度可管理,OSGi技术提供一种面向服务的架构,它能使这些组件动态地发现对方。

OSGi联盟已经开发了例如像HTTP服务器、配置、日志、安全、用户管理、XML等很多公共功能标准组件接口。这些组件的兼容性插件实现可以从进行了不同优化和使用代价的不同计算机服务提供商得到。然而,服务接口能够基于专有权基础上开发。

OSGi的主要职责就是为了让开发者能够创建动态化、模块化的Java系统。

OSGi 框架

OSGi框架从概念上可以分为三层:模块层、生命周期层和服务层。

  • Module Layer:模块层主要涉及包及共享的代码;
  • Lifecycle Layer:生命周期层主要涉及Bundle的运行时生命周期管理;
  • Service Layer:服务层主要涉及模块之间的交互和通信。

模块层

模块层是 OSGi 框架中最基础的部分。

OSGi 的模块化,是通过为 Jar 包添加metadata 来定义哪些类该暴露,哪些类该隐藏,其控制单元叫做 Bundle(jar 包)。

Bundle

首先,必须先了解一个基本概念——什么是Bundle?

什么是 Bundle ?

bundle 是以 jar 包形式存在的一个模块化物理单元,里面包含了代码,资源文件和元数据(metadata),并且jar包的物理边界也同时是运行时逻辑模块的封装边界。

如何定义 Bundle

Bundle 是 OSGi 中的基本组件,其表现形式仍然为 Java 概念中传统的 Jar 包。

通过 META-INF 目录下的 MANIFEST.MF 文件对其予以进一步的定义。

通常一个 MANIFEST.MF 文件的内容如下:

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Util
Bundle-SymbolicName: com.ibm.director.la.util
Bundle-Version: 1.0.0
Bundle-RequiredExecutionEnvironment: J2SE-1.5
Import-Package: org.osgi.framework;version="1.3.0"
Export-Package: com.ibm.director.la.util;uses:="org.osgi.framework"
Bundle-ClassPath: lib/junit.jar,

MANIFEST.MF 文件存储的实际上是 Bundle 的元数据。

元数据的内容可以精确的定义 Bundle 的各种特征,同时能更好的对 Bundle 进行标识同时帮助用户对Bundle进行理解。

生命周期层

生命周期层在OSGi框架中属于模块层上面的一层,它的运作是建立在模块层的功能之上的。

生命周期层的主要功能是控制动态安装、开启、关闭、更新和卸载的bundles。

生命周期层让你能够从外部管理应用或者建立能够自我管理的应用(或者两者的结合),并且给了应用本身很大的动态性。

前面已经了解了 Bundle 的概念和作用。但是要真正使用 Bundle,需要使用生命周期层的API,来和OSGi框架的生命周期层进行交互。

在标准的Java编程中,可以通过将jar包放到classpath中来使用它。而bundle则不是这样,Bundle只有在被安装(install)到一个OSGi框架的运行实例中才能用起来。并且OSGi框架支持对这些bundle完整的生命周期管理,并且支持这些管理操作在应用执行完成。

下图为 Bundle 生命周期的状态转移图:

重要接口

生命周期层的API主要是由以下三个核心接口来组成的:BundleActivator,BundleContext 和 Bundle。

  • BundleActivator:让你能够捕捉bundle的start和stop事件,并对这两个事件作出自定义的反应。
  • BundleContext:一个bundle在框架中的执行时上下文,这个上下文提供了和框架进行交互的方法。
  • Bundle:在逻辑上表示了一个bundle,OSGi环境中的一个物理bundle对应了一个bundle对象。该对象中包含了bundle的基本信息和bundle生命周期的控制接口。

服务层

一个OSGi 服务就是注册到 OSGi 框架中的一个 Java 对象。注册的时候可以设置这个 Service 的属性。而在获取 Service的时候可以根据属性进行过滤。

Bundle 可以通过 Bundle的上下文去注册Service或去查询Service。

一个提供服务的bundle可以发布POJO作为服务的实体;一个使用服务的bundle可以通过这个注册表找到和绑定服务。 

发布服务

为了让别的bundle能发现这个服务,你必须在发布它之前对其进行特征描述。这些特征包括接口的名字(可以是名字的数组),接口的实现,和一个可选的java.util.Dictionary类型的元数据信息。

String[] interfaces =  new String[]{StockListing.class.getName(), StockChart.class.getname()};  
Dictionary metadata =  new Properties();  
metadata.setProperty(“name”, “LSE”);  
metadata.setProperty(“currency”, Currency.getInstance(“GBP”));  
metadata.setProperty(“country”, “GB”);  
ServiceRegistration registration = bundleContext.registerService(interfaces, new LSE(), metadata); 

在上面的代码中,我们得到了 ServiceRegistration 对象,我们可以用这个对象来更新服务的元数据:

registration.setProperties(newMetadata);

也可以直接就把这个服务移除:

registration.unregister();

需要注意的是这个对象不能和其他 Bundle 共享,因为它和发布服务的bundle的生命周期相互依存。

也就是说,如果这个 Bundle 已经不在框架执行环境中存在,那么这个对象也不应该存在了,“皮之不存毛将焉附”就是这个道理。

试想如果这个 ServiceRegistration 共享给了其他的 bundle(具体的说就是其他bundle中存在对这个对象的引用),那么发布服务的那个bundle即使被移除了,由于其他bundle中的引用依然存在,那么垃圾处理机制不会抹去这个对象,这样不但于理不合,而且实际上这个对象也是不可用的,因为这个对象所依存的bundle已经不在了。 代码中的参数new LSE()是一个POJO,这个对象不需要实现任何OSGi类型或者使用标注,只要满足服务约定(这里就是接口)就可以了。

此外,如果在删除发布的服务之前bundle停止了,框架会帮助你删除这些服务。

发现和绑定服务

以下是一个根据实现的接口名称获得的服务的最简单方法:

ServiceReference reference =  
bundleContext.getServiceReference(StockListing.class.getName());

注意这里的reference是服务对象的间接引用,可是为什么要用间接引用而不直接返回那个实际的服务对象呢?

实际上是为了将服务的使用和服务的实现进行解耦,将服务注册表作为两者的中间人,达到跟踪和控制服务的目的,同时还可以在服务消失了以后通知使用者。

这个方法的返回类型是ServiceReference,它可以在bundle之间互享,因为它和使用服务的bundle的生命周期无关。

参考资料

OSGi入门篇:模块层

OSGi入门篇:生命周期层

OSGi入门篇:服务层

OSGi原理与最佳实践

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏逸鹏说道

浅谈命令查询职责分离(CQRS)模式

在常用的三层架构中,通常都是通过数据访问层来修改或者查询数据,一般修改和查询使用的是相同的实体。在一些业务逻辑简单的系统中可能没有什么问题,但是随着系统逻辑变得...

2554
来自专栏腾讯云API

【转】腾讯云 TCCLI 实践分享

原文地址:https://cloud.tencent.com/developer/article/1158013

1403
来自专栏Golang语言社区

Go语言实践:从新手入门到上线真实的小型服务所遇到的那些坑

摘要: Teamwork团队在去年写了近20万行Go代码,建造了一堆速度奇快的小型HTTP服务,本文列出了他们总结的9条经验教训。 为什么选择Go语言?Go...

3316
来自专栏北京马哥教育

有关bash,我希望我能知晓的十件事

1495
来自专栏Android 研究

APK安装流程详解1——有关"安装ing"的实体类概述

该类包含了从AndroidManifest.xml文件中收集的所有信息。 PackageInfo.java源码地址 通过源码我们知道PackageInfo是...

982
来自专栏SDNLAB

OpenStack Neutron之持续测试

一.OpenStack持续测试概述 众所周知,OpenStack作为一个特大型软件开发项目,有着数千人的开发人员,每天要处理千计提交的代码,几千条Gerrit评...

40611
来自专栏Android-薛之涛

Activity启动模式(launchMode)详解

      好了,今天想整理一下Activity启动模式的笔记,毕竟项目开发中有涉及且之前面试都有问道,抽周末做个总结。

862
来自专栏我就是马云飞

Android MVP升级路(二)时尚版

前言 第一篇文章的结尾对时尚版MVP结构做了一个简单的预告,下面继续从时尚版MVP说起。 时尚版MVP架构-Model层的优化 在从乞丐版MVP架构优化成平民版...

3577
来自专栏james大数据架构

Android实现TCP断点上传,后台C#服务实现接收

终端实现大文件上传一直都是比较难的技术,其中涉及到后端与前端的交互,稳定性和流量大小,而且实现原理每个人都有自己的想法,后端主流用的比较多的是Http来实现,因...

2399
来自专栏CSDN技术头条

OpenStack Neutron之持续测试

一、OpenStack持续测试概述 众所周知,OpenStack作为一个特大型软件开发项目,有着数千人的开发人员,每天要处理千计提交的代码,几千条Gerrit...

3638

扫码关注云+社区