OSGI动态加载删除Service bundle
OSGi模块化框架是很早就出来的一个插件化框架,最早Eclipse用它而出名,但这些年也没有大热虽然OSGi已经发布了版本1到版本5。现在用的最多的,也是本文讲述基于的是Equinox的OSGi实现,同时也是Eclipse核心,Spring Dynamic Module也是基于Equinox。OSGi框架为java系统提供了一个通用的容器,该系统中的 bundle,无需停止系统,即可实现 bundle 的安装、卸载。OSGi是Java中目前唯一的一个模块化、动态化的规范。在模块化方面OSGi联盟已经研究了很多年了,因此OSGi规范对于模块的物理隔离、模块的交互、多版本这些方面都有了非常完善的机制,并且也得到了现在几乎所有的App Server厂商或开源社区的认可,但至今没有被JAVA纳入语言级(有待观察)。OSGi的突出特点有:
- 可以动态加载、更新和卸载模块而不用停止服务
- 实现系统的模块化、版本化,允许多版本bundule同时服务
- Service model允许模块/插件相互依赖但松耦合,分享服务更简单
OSGi运行在JVM之上,其架构图如下图所示:
OSGi适用场景
很多人错误的使用了OSGi, 套用了OSGi架构把系统复杂化。在我看来,OSGi的用处在于“模块化”和“热插拔”。模块化包括模块化、版本化和面向服务的设计。热插拔也就是说模块/bundle的热插拔,它可以实现更新和升级模块/bundle(即系统的一部分)而无需重启整个系统。
如果你的系统套用了OSGi架构,bundle的相互依赖关系复杂,又没有bundle动态加载、动态更新、动态卸载和动态监听的机制,都是静态启动所有bundle,那就是为了OSGi架构而OSGi架构,把问题复杂化了。其代价也是很大的,因为原来你的jar包用maven来处理依赖关系和自动更新也很方便,而由于整个系统建立在OSGi规范上,你的应用所依赖的其他组件也“不得不”迁移到OSGI上来,再加上OSGI独特的ClassLoader设计,使bundle间的类互相访问受到一定的约束,一切都需要迁移到OSGi的约束上来。
举个例子来说,就像Eclipse提供了动态加载、更新和删除插件的机制,因为它里面有一个插件注册和反注册的接口和插件加载、更新和删除的监听线程,这样允许你动态加载、更新和删除Eclipse插件而无需重启Eclipse。当然,如果你当前进程调用了某插件,比如js语法高亮,而某插件更新了,那么当前的js实例还是需要重新打开的。但整个Eclispe无需重启。
Java模块化的难点
OSGi的一个重要特性就是模块化,OSGi提供了一套模块化的体系,这其中则会有明确的模块之间接口暴露以及依赖的定义,因此能够更好的实现高内聚和低耦合。那么,Java模块化难点在哪?模块的实现和传统的编程方法确实有一些差别,主要体现在模块之间类访问的隔离、版本选择这两个方面。如希望更好的设计模块化的系统,开发者需要掌握ClassLoader机制、模块之间类的交互方法(这包括了模块怎么样对外提供可访问的package、怎么样访问其他模块提供的package、如何选择适合版本的package等)。如果不懂以上这些,贸然套用OSGi框架会误入歧途。
重要概念:Bundle
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 的成员访问控制机制。
Bundle通过MANIFEST.MF进行自描述,下面是一个例子:
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Popup Plug-in
Bundle-SymbolicName: com.example.myosgi; singleton:=true
Bundle-Version: 1.0.0
Bundle-Activator: com.example.myosgi.Activator
Require-Bundle: org.eclipse.ui,
org.eclipse.core.runtime
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Bundle类隔离机制
每个Bundle均为独立的ClassLoader,是java动态化实现的基础。默认情况下有Boostrap classLoader (jre/lib/classes)、Extension classloader (jre/lib/ext)、 System classloader (classpath指定),应用可以自行实现classloader及动态的加载类,或加载特定目录下的类。
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状态。
osgi> ss
"Framework is launched."
id State Bundle
15 STARTING com.example.serviceconsumer_1.0.0.X
16 RESOLVED com.example.serviceprovider_1.0.0.X
下面的图更详细的解释了这一点:
OSGi Service
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 the Device and UPnP APIs
- Expose java code running in OSGI to an external network, e.g. via the UPnP or SOAP protocols.
- Bundle configuration, using the Configuration Manager
实际做法来看,通常会把接口和实现分开。接口放到一个bundle里面。实现(service)放到另外一个bundle里面,类似下面的图示中,bundle A和B是Service,其interface放到Bundle C:
也可以是提供一个jar包,里面定义了扩展接口,然后规定新的扩展bundle必须实现该jar包里面定义的interface。实现示意图如下所示(OsgiCommand接口定义在扩展点jar包里面,新的bundle必须包含):
Bundle的Service之间交换方式和注册方式:
- 通过bundleContext.registerService注册服务,然后通过bundleContext.getServiceReference获取服务(不推荐)
- 使用监听器 listeners
ServiceListener 和ServiceTracker 提供bundle和service的动态监听,ServiceTracker可以动态监听未来的bundle和service(OSGi Release 2提供的ServiceTracker ,一般推荐)
- 通过Declarative Service (OSGi DS,或者Spring Dynamic Module (DM))的方式(OSGi Release 4开始,重点推荐!)
第二种通过ServiceTracker 来查询或侦听服务注册和注销的例子代码:
package com.ibm.osg.example.mygetservice; import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.util.tracker.ServiceTracker;
import com.ibm.osg.example.mtservice.MyTestService; public class MyBundleActivator
implements BundleActivator, Runnable
{
private boolean done=false;
private ServiceTracker testServiceTracker; // Bundle Activator Start Method
public void start(BundleContext context)
{
/* Here we initialize and open our ServiceTracker.
It will track any service registering under
the "com.ibm.osg.example.mtservice.MyTestService"
interface.
*/ testServiceTracker =
new ServiceTracker(context,
"com.ibm.osg.example.mtservice.MyTestService",
null);
testServiceTracker.open(); // Here we start a thread that will continue
// to use our service until
// the bundle is stopped. Thread t = new Thread(this);
t.setName("mygetservice thread");
t.start(); }
/*Bundle Activator Stop Method -- here we stop
the thread and close the
ServiceTracker*/ public void stop(BundleContext context)
{
done=true;
testServiceTracker.close();
}
//Here is a method that uses the service
//we are tracking. First we get
//the service
//from the tracker, then we call its printMessage
//method. public void useService(String message){
MyTestService testService = (MyTestService)
testServiceTracker.getService(); if( testService != null )
{
// If the service is available then use it.
testService.printMessage(message);
}
else{
// If the service is not available then perform an acceptable action.
// Here we just print the message to standard out and indicate the service
// was not available.
System.out.println("No MyTestService available - " + message);
}
} // Simply continues to use the test service
// every second until the done flag is set.
public void run(){
int i = 0;
done = false;
while (!done) {
useService("message from test " + i++);
try{
Thread.sleep(1000);
}
catch( InterruptedException ie ){
}
}
}
}
OSGi简单起步
从Eclipse创建OSGi的bundle是非常简单的,简单起步可以参考这几篇文章:<Creating a new OSGi Bundle using Eclispe>,以前这篇。
Slideshare: OSGi理论与实战
OSGi动态加载删除bundle
- 使用监听器 listeners
ServiceListener 和ServiceTracker 提供bundle和service的动态监听,ServiceTracker可以动态监听未来的bundle和service(OSGi Release 2提供的ServiceTracker ,一般推荐)
- 通过Declarative Service (OSGi DS,或者Spring Dynamic Module (DM))的方式(OSGi Release 4开始,重点推荐!)
具体实现:
分布式OSGi(Distributed OSGi)
OSGi容器可以包含几千个bundlue没有问题,但如何应对几十万个的情况?如何像EJB3一样具有分布式部署和便携性呢?有一个OSGi的子项目:分布式OSGi(Distributed OSGi)。
上图是一个demo演示,两个分布式OSGi Container,都部署了Greeter接口bundle,都基于分布式OSGi实现,能实现分布式调用OSGi Service。分布式OSGi(Distributed OSGi)还可以与RESTful Service (JAX-RS / JSR-339)整合。分布式OSGi有几十万个bundle怎么管理,这是个麻烦,而且如何启动停止,启动顺序怎么样?可管理性是个麻烦,ACE项目试图解决这个事情。
DOSGi的原理(由Distribution provider来给OSGi Service创建Endpoint,使这些Service在OSGi Container外部可访问,另外一端则创建代理;此外,有监听器来侦听OSGi Service的创建和启停等):
分布式OSGi与ZooKeeper
ZooKeeper是Hadoop的一个子项目,它是一个针对大型分布式系统的可靠协调系统,提供的功能包括:配置维护、名字服务、分布式同步、组服务等。ZooKeeper的目标就是封装好复杂易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户。
分布式OSGi(Distributed OSGi)在Discovery这一块使用了ZooKeeper。所谓Discovery模块就是用来发现和侦听分布式的远端的可用的Endpoints。Discovery Ditributed with Zookeeper的架构图:
参考:DOSGi使用ZooKeeper server的安装和Demo。
就写到这把,具体的代码就不放上来了,公司的项目保密要求。原理上面都讲了,自己去研究吧。
OSGI动态加载删除Service bundle的更多相关文章
- 动态加载/删除css文件以及图片预加载
动态加载/删除css文件以及图片预加载 功能模块页面 最近,工作中遇到了一个比较奇葩的需求:要在一个页面(PC端)增加一个功能模块,但是这个页面在不久之后要重构,为了新增加的模块可以继续复用, ...
- svg的animate动画动态加载删除遇到删除animate后再次加载的animate动画没有效果问题
svg上有多个圆圈,当选中特定圆圈后给其加上animate动画效果,并把其他圆圈的animate效果去除. 第一次选择一个点实现动画效果完全达到效果,因为是第一次所以不需要把其他圆圈的animate子 ...
- [AngularJS] 使用AngularAMD动态加载Service
[AngularJS] 使用AngularAMD动态加载Service 前言 「使用AngularAMD动态加载Controller」:这篇文章里介绍如何使用AngularAMD来动态加载Contro ...
- 动态加载框架DL分析
动态加载框架DL分析 插件化开发,主要解决三个问题1.动态加载未安装的apk,dex,jar等文件2.activity生命周期的问题,还有service3.Android的资源调用的问题 简单说一下怎 ...
- [转载] Android动态加载Dex机制解析
本文转载自: http://blog.csdn.net/wy353208214/article/details/50859422 1.什么是类加载器? 类加载器(class loader)是 Java ...
- Android中的动态加载机制
在目前的软硬件环境下,Native App与Web App在用户体验上有着明显的优势,但在实际项目中有些会因为业务的频繁变更而频繁的升级客户端,造成较差的用户体验,而这也恰恰是Web App的优势.本 ...
- APK动态加载框架(DL)解析
转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/39937639 (来自singwhatiwanna的csdn博客) 前言 好久 ...
- Android 动态加载 (一) 态加载机制 案例一
在目前的软硬件环境下,Native App与Web App在用户体验上有着明显的优势,但在实际项目中有些会因为业务的频繁变更而频繁的升级客户端,造成较差的用户体验,而这也恰恰是Web App的优势.本 ...
- shiro不重启动态加载权限
最近一朋友让我帮他做一个后台权限管理的项目.我就在我原来的项目加加改改但是还是不理想,查了不少资料也走了不了弯路...... shiro基本的配置我就不多说了这个很简单自己查查资料就完成----下面是 ...
随机推荐
- java中的标识符、关键字、保留字
Java中关键字(keyword)和保留字(reservedword) Keyword :Java的关键字对java的编译器有特殊的意义,他们用来表示一种数据类型,或者表示程序的结构等. Reserv ...
- 鼠标经过,显示悬浮DIV
属牛人的本命佛是虚空藏菩萨.属牛人可佩戴属牛黄玉本命佛来提升财运,黄玉的金黄色代表蒸蒸日上,而“金黄”也就是“黄金”的到(倒)来,象征着富贵与财气,佩戴可以招财招富贵,同时黄玉亦是希望之石,可带来智慧 ...
- 小组spring计划列表
我们的会议地点:石家庄铁道大学三栋420. 每天进行会议的时间是早上七点钟. 会议内容:主要是讨论当日进行哪一个进程.
- maven之web工程的搭建
参考之前jave application的工程创建的步骤,我们只需要修改最后一步 这样就创建了个web maven工程 与java application应用程序的区别,还有别的区别这里不做多的阐述. ...
- java基础-day20
第09天 IO流 今日内容介绍 u File类 u 字符流与字节流 第1章 File类 1.1 File概述 打开API,搜索File类.阅读其描述:File文件和目录路径名的抽象表 ...
- poj3061
#include<stdio.h> #include<iostream> using namespace std; #include<algorithm> cons ...
- Uval4726-数形结合的思想
题意:给定一段01序列,求一段长度不小于L的连续序列,使其平均值最大 思路:一看就想到了斜率优化,但是用基本的推公示一直没推出来,看了别人的代码,像推出斜率的式子一直没弄出来..后来一看别人写的题解, ...
- CentOS 7.2通过yum安装MairaDB 10.1
CentOS 7.2自带的yum源中mysql已经被替换成了mariadb,然而却是5.5版本,匹配mysql5.5,想要使用mysql 5.7的特性需要mariadb 10.0或10.1版本,10. ...
- [翻译]第二天 - Visual Studio 中的 .NET Core 模版一览
原文: http://michaelcrump.net/part2-aspnetcore/ 免责声明:我不是 .NET Core 开发团队的一员,并且使用的是公开.可用的工具. 简介 该系列文章的完整 ...
- 【推荐】介绍两款Windows资源管理器,Q-Dir 与 FreeCommander XE(比TotalCommander更易用的免费资源管理器)
你是否也像我一样,随着硬盘.文件数量的增加,而感到对于文件的管理越来越乏力. 于是我试用了传说中的各种软件,包括各种Explorer外壳,或者第三方资源管理器. 最后我确定下来经常使用,并推荐给您的是 ...