OSGi开源框架介绍
当前的OSGi开源框架主要包含如下几个:
Equinox
最知名,也是更新最频繁的,由于Eclipse 基金的支持,其功能越来越完善,笔者后续的具体开发都是基于该框架来实现的。当前已发布版本是3.3.1 与Eclipse版本相同,实现了OSGi R4规范,并提供很多平台性质的服务,包括:常用功能模块、日志模块、Web服务器模块、Servlet模块、JSP解析模块等等。由于其与Eclipse 的天然联系,使得开发基于Equinox的应用程序变得很简单,笔者推荐采用此框架进行二次开发。具体内容可以从http://www.eclipse.org/equinox/下载。
Knopflerfish
很早的,也很优秀的一个OSGi框架,也实现了OSGi R4标准,去年十一月发布了其2.0.2版本。该项目的宗旨在于创建一个易于开发的OSGi 平台,与Equinox不同之处在于它本身提供一些小应用实例,包括一个可视化控制台等,也提供基于Eclipse的插件。具体内容可以从http://www.knopflerfish.org/下载。
Felix
很新的一个OSGi框架,社区很活跃,更新频率高,是Apache的开源项目。该项目2007年8月才出1.0 版,也实现了OSGi R4规范,也提供相关的基础服务和扩展服务功能。具体内容可以从http://felix.apache.org/site/index.html下载。
OSGi开发环境部署
讲了那么多原理,如果不动手实践一下,总是难以令人信服的。那么现在我们就开始动手搭建开发环境吧。
首先,你需要准备好Eclipse笔者用的是Eclipse 3.3.1,还有从Equinox网站上下载到的Equinox SDK。
其次,将Equinox SDK解压,解压后是一个Eclipse目录,将该目录下的所有内容拷贝至你的Eclipse安装目录下,就像平时手动安装Eclipse插件一样。
最后,测试下是否安装成功。启动你的Eclipse,选择Run>Open Run Dialog…在弹出的界面中,如果出现了OSGi Framework的选项,那基本上就是成功了。点击新建一个OSGi Run方式,这时会列出一系列的加载组件,你可以检查一下,如果里面有org.eclipse.OSGi ,org.eclipse.OSGi.services和一系列以org.eclipse.equinox开头的组件,那么就真的安装成功了。选中org.eclipse.OSGi和org.eclipse.OSGi.services,点击Run 按钮,控制台会出现“OSGi>”的提示,输入“ss”,就会看到你运行的这两个Bundles的ID和状态了。每次输入错误的时候,控制台会打印出完整的命令列表,读者可以在此参考。
OSGi版HelloWorld
到了真的写一个HelloWorld的时候了,该应用设计如下图:
这个应用包含五个Bundles:SayHello Bundle包含一个接口,只有唯一的方法sayHello();BobSays、RodSays、KentSays三个Bundles 分别实现了三个具体的sayHello();而SayHelloService Bundle提供了说hello的机会,是具体的一个服务应用,在功能上有点类似于main函数的味道。这个HelloWorld demo的目的不但可以让读者小试牛刀,而且可以同时体会一下OSGi最大的优点——服务状态的可更改性。BobSays、RodSays、KentSays实现了SayHello暴露的接口,它们是sayHello 的具体执行者,但是在SayHelloService调用的过程中,我们可以动态的改变到底是谁来说。为了实现这个demo,还需要简单介绍一下OSGi 最简单的实现机制:OSGi Bundles之间包的依赖关系。每一个OSGi Bundle的类文件可分为私有的、引入的、暴露的三种,如下图所示
在OSGi 中Exported Classes是以包的方式暴露的,如图所示,SayHello中暴露了接口所在的包,对应的BobSays等三个Bundles和SayHelloService Bundle都引入了该包,这是OSGi中最简单的通信方式,OSGi规范中推荐使用面向服务的通信方式,这里只是举一个简单的实例,因此不用做的那么复杂。
回到正题,启动你的Eclipse,新建一个名为SayHello 的plug-in project,在Target Platform. 选项中,选择an OSGi Framework:Equinox。笔者自己设置了Activator路径为org.OSGi.demo.sayHello.Activator,每个Activator都具有两个方法,start()和stop(),这两个方法是该bundle 启动、停止的时候,调用的方法,通常在这里注册、初始化或注销该Bundle 服务的过程,这里不需要更改任何Activator中的内容,用系统自动生成的就可以了。在建立好项目后,会出现对SayHello 项目的配置,这里可以通过dependencies 选项卡,设置需要的plug-in和引入的package;可以通过runtime选项卡的设置,确定暴露哪些包。我们新建一个org.OSGi.demo.say包,并建立SayHello接口,只有一个返回void的方法sayHello(),并将此包设为暴露的。这些设置都保存在项目的META-INF目录下的MANIFEST.MF文件中,以后要更改的话,只需打开该文件即可。 SayHello接口的代码如下:
以下是引用片段: public interface SayHello { public void sayHello(); } |
同样类似的新建一个名为BobSays的plug-in project。笔者设置的包为org.OSGi.demo.bob,这里需要在配置dependencies的时候,将包org.OSGi.demo.say引入。创建新的类BobSays,代码如下:
以下是引用片段: public class BobSays implements SayHello { public void sayHello() { System.out.println(“Bob says “Hello OSGi world””); } } |
这里需要覆写在BobSays Bundle中的Activator的两个方法,具体代码如下:
以下是引用片段: public class Activator implements BundleActivator { private ServiceRegistration serviceReg = null; public void start(BundleContext context) throws Exception { serviceReg = context.registerService(SayHello.class.getName(), new BobSays(), null);// 1 } public void stop(BundleContext context) throws Exception { if (serviceReg != null) serviceReg.unregister();// 2 } } |
完成的主要功能是:1、在启动服务的时候,注册BoySays服务为一个SayHello服务;2、在停止服务的时候,从上下文中卸载该服务。
类似的创建KentSays、RodSays两个project。
最后,创建一个名为SayHelloService的plug-in project。笔者设置的包为org.OSGi.demo.service,同样在配置dependencies的时候,将包org.OSGi.demo.say引入。创建SayHelloService类,代码如下:
以下是引用片段: public class SayHelloService { private SayHello say; public void helloWorld() { for (int i = 0; i < 10; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); System.err.println(“Thread can’t sleep”); } say.sayHello(); } } public void setSay(SayHello say) { this.say = say; } } |
这里采用依赖注入的方式,所以有一个setSay()方法,来设置一个具体的SayHello。helloWorld()方法就是调用特定的SayHello.sayHello()来完成的,用10秒钟的时间打印十次sayHello()的具体内容。该Bundle 的Activator代码如下:
以下是引用片段: public class Activator implements BundleActivator { private ServiceRegistration serviceReg = null; public void start(BundleContext context) throws Exception { SayHelloService sayService = new SayHelloService(); serviceReg = context.registerService(SayHelloService.class.getName(), sayService, null);// 1 ServiceReference serviceRef = context .getServiceReference(SayHello.class.getName());// 2 sayService.setSay((SayHello) context.getService(serviceRef));// 2 sayService.helloWorld();// 3 } public void stop(BundleContext context) throws Exception { if (serviceReg != null) serviceReg.unregister(); } } |
完成的主要功能是:1、注册SayHelloService服务;2、获取一个的SayHello服务;3、并注入到SayHelloService服务中,现在注入的服务是从服务上下文中具体获取的,而到底是哪个,只有在运行时状态才能决定。
至此,所有的Bundles我们都已经完成了,选择Open Run Dialog……,并选中上述五个Bundles 和OSGi 核心Bundle,点击Run按钮。输入“ss”,列出了6个Bundles 的状态,此时,如果你的SayHelloService Bundle状态是Resolved,那么你可以通过命令“start‘SayHelloService Bundle 状态的id’”,启动SayHelloService,此时你会看到打印出的10条hello world信息。读者可以手动利用用命令“start”和“stop”改变sayHello的具体执行者,动态的更换实际sayHello的执行者。这个简单的HelloWorld应用,可以说明SayHelloService在具体执行的过程中行为是可动态改变的,并且改变只是局部的。
小结
读完本文,实际动手做过HelloWorld,想必读者对OSGi框架也应该有所了解了,OSGi框架在国外关注率是挺高的,但是在国内的推广和使用却不够广泛,可能是因为OSGi字面上的意思太过于抽象,因此笔者在这里将这个优秀的框架介绍给大家,本片只是一个简单的介绍,并不涉及OSGi框架深入的知识。
我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。
我原创,你原创,我们的内容世界才会更加精彩!
【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】
微信公众号
TechTarget
官方微博
TechTarget中国
作者
相关推荐
-
OpenStack VS CloudStack 比较?CloudStack还有前景吗?
-
Spring针对Java 8升级
Java 8刚刚在几周前发布。后来Spring Framework项目负责人发表了题为《企业项目中的Java 8》的文章。文中,指出那些著名的Java EE应用服务器如何不允许轻松升级。
-
软件项目成功:项目的处理
在软件项目成功的因素中有我们谈及了问题域和社区,然这两者并不是软件项目本身。你可以把分类当作问题领域连续讨论几个星期,但分类的问题跟实际执行分类的库并不一样。
-
Rails 4.1改进启动时间和响应布局
在经历了两个候选版本后,Rails团队刚刚发布了Rails 4.1.0。以“单点版本(point release)”发布意在说明更改向后兼容,可以无痛升级。