OSGi(开放服务网关协议,Open Service Gateway Initiative)技术是Java动态化模块化系统的一系列规范
优点:
1 可以动态加载、更新和卸载模块而不用停止服务
2 实现系统的模块化、版本化,允许多版本bundule同时服务
3 Service model允许模块/插件相互依赖但松耦合,分享服务更简单
缺点:
jigsaw的方式(java9),osgi显得笨重了
OSGi的用处在于“模块化”和“热插拔”。模块化包括模块化、版本化和面向服务的设计。热插拔也就是说模块/bundle的热插拔,它可以实现更新和升级模块/bundle(即系统的一部分)而无需重启整个系统
OSGi提供了一套模块化的体系,这其中则会有明确的模块之间接口暴露以及依赖的定义,因此能够更好的实现高内聚和低耦合。那么,Java模块化难点在哪?模块的实现和传统的编程方法确实有一些差别,主要体现在模块之间类访问的隔离、版本选择这两个方面。如希望更好的设计模块化的系统
1 Bundle — A bundle is a JAR file with special OSGi entries in its manifest and containing classes, resources, and other JARs。Bundle,可以将其理解为自描述的 JAR 文件。Bundle在OSGi中是部署的最小单位,因此,可以把它理解为模块。在 bundle 的 manifest 文件中,会有对本 bundle 的标识、提供的功能 (Export-package) 及依赖性 (Import-Package/Require-Bundle) 的定义。每个 bundle 在运行时自己的类加载器 (Class Loader),这样可以做到一方面把不同的 bundle 里面的类区别开来,当 bundle 被卸载时,只有这个 bundle 的类加载器中的信息会丢失;另一方面,可以在自己的 bundle 内部充分利用 Java 的成员访问控制机制。
2 Bundle类隔离机制
每个Bundle均为独立的ClassLoader,是java动态化实现的基础。默认情况下有Boostrap classLoader (jre/lib/classes)、Extension classloader (jre/lib/ext)、 System classloader (classpath指定),应用可以自行实现classloader及动态的加载类,或加载特定目录下的类。
3 Bundle的生命周期
Lifecycle — A lifecycle is the sequence of states a bundle goes through: uninstalled, installed, resolved, starting, stopping, active. 生命周期图如下所示:
bundle状态变为Resolved并不表示能提供服务,所以启动所有的bundle不表示类都已经加载到内存了。Resolve bundle做以下的几件事情:寻找bundle依赖的包是否存在以及被resolve,寻找匹配的import package,required bundle,如寻找则进入检查,检查没有冲突就形成绑定关系,以便加载类的时候能直接加载(但仅仅Resolved,不代表类被加载了),目前受益良多如果你的BundleActivationPolicy是LAZY惰性加载,bundle.loadClass()调用才会到达Active状态。如果你的bundle的MANIFEST.MF中配置的Bundle-activator存在,那就调用其start方法,从starting进入active状态
bundle 可以处于以下状态中的一种:
l INSTALLED — 成功安装 bundle
l RESOLVED — 所有 bundle 需要的 Java 类都准备好了。这个状态标志着 bundle 已经是
启动就绪或者是已经停止。
l STARTING — 正在启动 bundle。调用了 bundle 激活器的 start 方法,而且还没有从方法
中返回。
l ACTIVE — bundle 已经启动完毕,正在运行中。
l STOPPING — 正在停止 bundle。调用了 bundle 激活器的 stop 方法,而且还没有从方法
中返回。
l UNINSTALLED — bundle 已经卸载完毕,不能进入其他状态.
4 Service — A service is an object instance exposed under the one or more interfaces that it implements and a map of properties. 简单来说,Service model允许每个bundle对外分享一组服务,其它的bundle都可以调用这些接口的服务。这也就是OSGi bundle之间调用的方式。Service可以用来:
Export functionality from a bundle to other bundles
Import functionality from other bundles
Register listeners for events from other bundles
Expose external devices, such as UPnP devices or even hardware, to other OSGi bundles. See theDeviceandUPnPAPIs
Expose java code running in OSGI to an external network, e.g. via the UPnP orSOAPprotocols.
Bundle configuration, using theConfiguration Manager
实际做法来看,通常会把接口和实现分开。接口放到一个bundle里面。实现(service)放到另外一个bundle里面,类似下面的图示中,bundle A和B是Service,其interface放到Bundle C:
也可以是提供一个jar包,里面定义了扩展接口,然后规定新的扩展bundle必须实现该jar包里面定义的interface。实现示意图如下所示(OsgiCommand接口定义在扩展点jar包里面,新的bundle必须包含):
Bundle的Service之间交换方式和注册方式:
1 通过bundleContext.registerService注册服务,然后通过bundleContext.getServiceReference获取服务(不推荐)
2 使用监听器listeners
ServiceListener和ServiceTracker提供bundle和service的动态监听,ServiceTracker可以动态监听未来的bundle和service(OSGi Release 2提供的ServiceTracker,一般推荐)
通过Declarative Service(OSGiDS,或者Spring Dynamic Module(DM))的方式(OSGi Release 4开始!)
5 分布式OSGi(Distributed OSGi)
OSGi容器可以包含几千个bundlue没有问题,但如何应对几十万个的情况?如何像EJB3一样具有分布式部署和便携性呢?有一个OSGi的子项目:分布式OSGi(Distributed OSGi)