前言
OSGI的精髓就是通过一个个的模块构建起整个应用系统,相对于普通开发模式而已,OSGI会强制开发人员对系统进行模块划分。因此如何对系统进行模块化的划分就显得很重要了,基本原则就是高内聚低耦合(在bundle内部高内聚,在bundle之间低耦合),每个团队负责指定的模块开发。指定好每个bundle的边界和职责,然后分别进行开发实现,这种方式非常有利于并行开发,提高工作效率。
传统的MVC开发模式一般会把系统分为Controller层、Service层、Dao层等等,每层一般会打成一个jar包。而OSGI的模块化概念一般建议以具体的业务功能进行模块划分,比如:登陆模块、a业务模块、b业务模块、数据操作模块(类似于Dao层)等待,各个模块之间有依赖关系,并且这些模块是可以独立更新的(热更新)。
OSGI的模块层规范,主要就是对如何进行模块化指定了相关规范,简单的理解就是如果配置模块的元数据文件MANIFEST.MF。
MANIFEST.MF配置详解
元数据文件MANIFEST.MF的配置信息分为三类:描述信息配置、唯一识别配置、可见性配置。描述信息配置:主要作用就是让使用者了解这个bundle,OGGI框架不会直接使用这些配置信息;唯一识别配置:这类配置信息主要作用就是用于在OSGI框架中唯一确定一个bundle;可见性配置:OSGI的模块化分为物理模块化和逻辑模块化,物理模块化的理解很简单就是把那些类放到bundle对应的jar包中,逻辑模块化就是bundle对内对外的可见边界,可见性配置的主要作用就是如何实现bundle的逻辑模块化。
描述信息配置
这部分是可选的,主要提供一些描述信息,方便使用者查阅。OGGI框架不会直接使用这些配置信息,也没有太多注意事项,根据业务需要选择性的使用即可:
Bundle-Name: my osgi test //根据自己的喜好随便写
Bundle-Description: do some test //描述信息,该模块是做什么的
Bundle-DocURL:http://www.xxxx.com //帮助文档地址
Bundle-Category: test //Bundle分类,随便写
Bundle-Vender:sky //Bundle供应商,是谁开发的
Bundle-ContactAddress: //供应商 联系地址
Bundle-Copyright: xxxx //供应商版权信息
唯一识别配置
是识别bundle的必须配置的信息。一共三个配置项:
Bundle-SymbolicName: com.sky.osgi.test
Bundle-Version: 1.0.0
Bundle-ManifestVersion: 2
Bundle-SymbolicName
Bundle-SymbolicName是Bundle唯一标识符,一般与java包的命名规则类似(域名反转),也可以选择其它命名方式,主要保证名字的唯一性即可。
Bundle-Version定义了Bundle的版本号,理论上Bundle-SymbolicName和Bundle-Version一起才可以保证在同一个OSGI运行框架下的唯一性。配置值 一般采用x.x.x的方式,其中x是一个数字,数字越大说明版本越新,另外也可以是采用1.1.1.beta表示版本号。
Bundle-ManifestVersion与OSGI规范的版本有关,不用过多解读,只需要记住是强制配置,并且值为2即可。
可见性配置
实现对bundle模块化的边界控制,是OSGI实现模块化的核心配置。主要用于描述类是Bundle内部可见,哪些类需要导出提供给其他Bundle使用。元数据的可见性配置包含下列三项:
Bundle-ClassPath:.,xxxx.jar
Import-Package:com.sky.osgi.client; version=”[1.0.0,2.00)”
Export-Package:com.sky.osgi.server; version=”1.0.0”
内部类路径
Bundle-ClassPath定义了Bundle的类路径,在OSGI框架里运行的每个Bundle都会使用一个独立的类加载器进行类加载,java是按需加载的 也就是在执行过程中用到了哪个类,就会到ClassPath下去找相应的class文件加载到方法区。Bundle-ClassPath配置的路径就是该Bundle对应的ClassLoader加载class文件的路径。
Bundle-ClassPath的默认路径是”.”,表示只加载当前jar包内的class文件。同时可以配置多个路径 并用“,”号间隔,这些路径都是相对于当即jar包位置的相对路径,ClassLoader查找顺序就是按照这个顺序进行。注意内嵌的jar包,是不能被直接加载的,需要配置到Bundle-ClassPath中才能被ClassLoader查找到。
导出内部代码
Export-Package配置项的作用是到出内部代码给其他Bundle使用,如果不配置该项 表示该Bundle不公开任何代码,只公开Export-Package配置值中配置的包路径下的类(不包含包下的类)。比如:Export-Package:com.sky.osgi.server; version=”1.0.0”,这个配置表明这个Bundle值公开了com.sky.osgi.server包下的类,其它即便是定义为Public的类 都是不公开的。
Export-Package可以导出多个包,其它Bundle可以通过Import-Package来导入自己需要的包。
导入外部代码
Import-Package配置项的作用是根据自己的需要导入其他Bundle公开的包,注意与Bundle-ClassPath的区别:Import-Package指定的包,不是自己的类加载器加载的,而是导出这个包的Bundle的ClassLoader加载的;而Bundle-ClassPath指定的路径是该Bundle自己的ClassLoader指定的路径。
同样的Import-Package也可以导入多个包。
另外 DynamicImport-Package: *,可以一次动态的导入多个需要的包,但由于存在相互依赖等问题不建议使用。
关于包的版本
在Export-Package和Import-Package一个包时,指定version版本号。在Export-Package导出时,可以指定一个特定的版本号;在Import-Package导入时可以指定一个特定的版本,也可以指定一个版本的区间,“[]”表示闭区间,“()”表示开区间,同时也可以是半开半闭。
比如:
Import-Package:com.sky.osgi.client; version=”1.0.0” //表示指定版本为大于等于1.0.0
Import-Package:com.sky.osgi.client; version=”[1.0.0,2.0.0)” //表示大于等于1.0.0,小于2.0.0
如果指定一个特定的版本,适配的区间为大于等于这个版本,如果不指定版本默认是0.0.0,也就是大于等于0.0.0,本质上也是一个区间。另外注意区分 包的版本与Bundle版本,前面讲的Bundle-Version是指定Bundle的版本。
Bundle内部加载顺序
在Bundle执行需要一个类时,会按照下列顺序进行查找:
1、如果类的包名是以java.开头的(也就是jdk中rt.jar中的类),会交给当前类加载器的父类加载器去查找并加载这个类。这种方法的好处是,对于JDK的公共API不需要多次加载。如果没有找到就抛出异常。
2、如果这个类的包路径在Import-Package配置的路径下,OSGI框架会委托给导出这个包的Bundle对应的类加载器查找并加载该类。如果没有找到直接抛出异常。
3、如果这个类的包路径在Bundle-ClassPath配置的路径下,会直接使用该Bundle自己的类加载器查找并加载该类。如果没有找到就抛出异常。
通过这3步查找顺序可以确定一个类在Bundle内部的一致性。
Bundle之间的一致性
目的:OSGI框架必须保证在多个Bundle中使用同一个版本的导出包。
由于Import-Package导入可能会遇到多个版本,那当前Bundle该如何选择呢?自动安装Bundle时 需要满足的原则是:
1、已解析的Bundle具有最高优先级,如果匹配到多个已解析的Bundle,按照先版本号后安装顺序进行匹配。
2、如果都未解析,同样是先版本号后安装顺序进行匹配。
所谓解析就是把给定Bundle的导入包与其它Bundle的导出包进行匹配的过程。解析依赖具有传递性:BundleA依赖BundleB,BundleA依赖BundleC,在解析BundleA时之前,必须先依次对BundleC、BundleB进行解析。
上述原则OSGI框架加载时自动遵守的。但也有特例,在动态加入Bundle时(在首次启动OSGI框架之后加入Bundle),有可能出现由于传递依赖导致的冲突,为了解决这个冲突在Export导出时,需要使用uses指令。例如:Export-Package: com.sky.server;uses:="com.sky.client"; version="2.0.0" 。这种场景不是很多,在具体用到时可以再查阅。
本文内容部分参考自《OSGI实战》
相关推荐
OSGi模块层是框架中最基础的部分,它实现了Java的模块化特性,但又与Java现有的模块化特性有所不同。 首先,文章介绍了模块化的概念。模块化是将大型系统分解为多个较小的逻辑单元,通过设定模块间的逻辑边界来改善...
OSGi模块层通过定义模块的命名空间和模块间的依赖关系,实现了模块的封装和隔离。 生命周期层定义了OSGi模块整个生命周期的管理。OSGi框架通过生命周期服务来控制模块的各个生命周期状态,例如INSTALLED、RESOLVED...
### OSGi模块管理系统及其动态管理特性 #### OSGi平台概述 OSGi(Open Service Gateway Initiative)服务平台为Java应用程序提供了全面、安全且易于管理的框架。这一框架的核心能力在于能够动态地管理部署在其内部...
OSGi.NET框架是一个参照了OSGi规范的模块化管理框架。框架为应用程序(组件(bundle))提供了一个标准环境。整个框架可以划分为一些层次: 1.运行环境 2.模块(Bundle) 3.生命周期管理 4.服务注册 5.扩展点...
总之,OSGi的生命周期层使得Java模块化开发成为可能,并为模块化应用提供了强大的生命周期管理能力。通过使用OSGi提供的API,开发者可以有效地管理应用各个模块的生命周期,实现应用的动态性、灵活性与可维护性,为...
在OSGi框架中,服务层是位于应用程序之上的一层,它为服务提供者和消费者之间的交互提供了一种机制。这一层的主要目的是实现组件之间的松耦合通信,即组件不需要知道彼此的具体实现细节,仅通过服务接口进行通信。 ...
在模块层,Bundle是OSGi的基本单位,包含必要的资源文件、manifest文件以及OSGi特定的文件夹。在运行时,获取类的过程是多步骤的,涉及到包查找、动态引用等多个层面。 生命周期管理层定义了Bundle的五种状态:安装...
OSGi模块化系统构建专家 OSGi(Open Service Gateway Initiative)是一种java模块化系统的构建专家,它提供了一个动态化的模块化系统,能够解决传统项目中的类加载器类冲突、jar包依赖性管理、包可见性管理和jar包...
OSGi框架从概念上可以分为三个层次:模块层、生命周期层和服务层。 模块层是OSGi框架中最基础的部分。它的主要功能是处理包和共享代码。模块化在OSGi中是通过为Jar包添加元数据(metadata)来实现的。元数据定义了...
在模块层之上是生命周期层,负责控制Bundle的动态安装、开启、关闭、更新和卸载。要实现这些功能,需要使用OSGi的API来与生命周期层进行交互,这一层给予了应用极大的动态性和自我管理能力。BundleActivator接口允许...
模块层是OSGi的核心,它定义了bundles的概念以及它们之间的依赖关系。每个bundle都有一个清单文件,其中包含了该bundle的元数据,如名称、版本和依赖的其他bundles。模块层还提供了类加载器隔离,这意味着每个bundle...
本文档主要针对OSGi.NET模块化框架使用进行了描述 OSGi.NET框架是一个参照了OSGi规范的模块化管理框架。框架为应用程序(组件(bundle))提供了一个标准环境。整个框架可以划分为一些层次: 1.运行环境 2.模块...
2. **模块层**:OSGI的基础是模块化,它定义了类的装载策略。每个模块称为bundle,有自己的类路径,并且通过MANIFEST.MF文件来描述其依赖和其他元数据。例如,在Apache Felix实现中,模块的加载是通过解析MANIFEST.H...
OSGi DAL 20131022.ppt"可能涉及到OSGi的设备访问层(Device Access Layer,DAL),这是OSGi用于连接和管理各种硬件设备的标准。"3. Introduction to OSGi.ppt"可能是OSGi的基础介绍,涵盖了其基本概念和使用方法。...
5. **深入探索模块化**:更深层次地探讨OSGi模块化的特点及其应用场景。 6. **向模块转变**:讨论如何将现有Java应用程序转换为基于OSGi的模块化应用程序。 7. **管理模块和应用程序**:提供关于如何在OSGi环境中...
在基于OSGi和Spring开发Web应用中,OSGi(Open Services Gateway Initiative)是一个开放标准,用于创建模块化Java应用程序。它允许开发者将应用程序分解为独立的模块,称为bundle,每个bundle都包含自己的类路径、...