首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 操作系统 >

[zz]osgi 一碎步

2012-07-30 
[zz]osgi 一小步网上有很多介绍osgi概念的文章,有兴趣的同学可以去google一下.这里写一个简单的例子,记录

[zz]osgi 一小步

网上有很多介绍osgi概念的文章,有兴趣的同学可以去google一下.这里写一个简单的例子,记录自己的学习历程,也希望对初学osgi的同学有所帮助.

osgi强调模块化与服务化,我们可以在不重启Java虚拟机的情况下切换一个服务的实现,达到动态更新目的.与spring不同的是,osgi可以动态绑定服务的实现,而Spring容器一旦启动就无法更改服务的实现,要想改变服务的实现,只有重新配置spring-bean文件,再重启 spring容器

下面例子就说明了这一点,我们要做的事情如下

    我们有一个HelloService,用户需要实现sayHello方法实现1,实现sayHello方法,输出HelloService1实现2,实现sayHello方法,输出HelloService2在运行时,将实现1切换到实现2,相当于模拟一种更新?卸载实现2,将实现还原为实现1,相当于模拟一种回滚

    创建以下几个maven工程

      hello 为主工程hello.service 该工程包含HelloService接口hello.service.impl1 该工程包含HelloService的实现hello.service.impl2 该工程包含HelloService的实现hello.service.consumer 该工程会使用HelloService以上四个工程皆为hello工程的module

      hello.service工程

      该工程为一个接口bundle,不包含BundleActivator

      其用处是为其他几个bundle提供HelloService接口,隔离hello.service.impl与hello.service.consumer

      package org.lazyman.osgi.hello.service;

      public interface HelloService {

      ?????? public void sayHello();

      }

      由于其他几个bundle需要使用到HelloService接口,该bundle需要导出HelloService接口,其MANIFEST.MF文件如下

      Manifest-Version: 1.0

      Created-By: Freewind

      Bundle-Version: 1.0.0

      Bundle-Name: Hello Service Bundle

      Bundle-Vendor: Freewind

      Bundle-ManifestVersion: 2

      Bundle-SymbolicName: hello.service

      Export-Package: org.lazyman.osgi.hello.service

      hello.service.impl1 工程

      该工程为HelloService的一个实现bundle,包含一个BundleActivator向osgi容器注册HelloService的实现,hello.service.consumer可以从osgi容器获取该实现,调用相关服务

      //HelloService 实现1

      package org.lazyman.osgi.hello.service.impl1;

      import org.lazyman.osgi.hello.service.HelloService;

      public class HelloServiceImpl1 implements HelloService {

      ?????? @Override

      ?????? public void sayHello() {

      ????????????? System.out?.println(“HelloService1″);//实现1

      ?????? }

      }

      //实现1的BundleActivator

      package org.lazyman.osgi.hello.service.impl1;

      import org.lazyman.osgi.hello.service.HelloService;

      import org.osgi.framework.BundleActivator;

      import org.osgi.framework.BundleContext;

      import org.osgi.framework.ServiceRegistration;

      public class HelloServiceActivator implements BundleActivator {

      ?????? private ServiceRegistration sr;

      ?????? @Override

      ?????? public void start(BundleContext context) throws Exception {

      ????????????? System.out?.println(“HelloServiceActivator1.start”);

      ????????????? //向osgi容器注册HelloService的实现1

      ????????????? sr = context.registerService(HelloService.class.getName(),new HelloServiceImpl1(), null);

      ?????? }

      ?????? @Override

      ?????? public void stop(BundleContext context) throws Exception {

      ????????????? sr.unregister();

      ?????? }

      }

      由于该bundle需要使用到HelloService接口及osgi的相关接口,该bundle需要导入相关的接口类,其MANIFEST.MF文件如下

      Manifest-Version: 1.0

      Created-By: Freewind

      Bundle-Version: 1.0.0

      Bundle-Name: Hello Service Impl1

      Bundle-Vendor: Freewind

      Bundle-ManifestVersion: 2

      Bundle-SymbolicName: hello.service.impl1

      Import-Package: org.lazyman.osgi.hello.service,org.osgi.framework

      Bundle-Activator: org.lazyman.osgi.hello.service.impl1.HelloServiceActivator

      hello.service.impl2 工程

      该bundle与hello.service.impl1类似,改变的是如下代码

      ?????? public void sayHello() {

      ????????????? System.out?.println(“HelloService2″);//实现2

      ?????? }

      篇幅所限,该工程其他的代码就不贴出了,有兴趣可参看下附件

      hello.service.consumer 工程

      该工程向osgi容器注册HelloService的服务监听器,当有HelloService服务注册时,服务监听器会取得该服务,并添加到 hello.service.consumer中,当HelloService卸载时,服务监听器会从hello.service.consumer去除该服务,具体如下

      //hello.service.consumer BundleActivator

      package org.lazyman.osgi.hello.service.consumer;

      import java.util.ArrayList;

      import java.util.List;

      import java.util.concurrent.ExecutorService;

      import java.util.concurrent.Executors;

      import java.util.concurrent.TimeUnit;

      import org.lazyman.osgi.hello.service.HelloService;

      import org.osgi.framework.BundleActivator;

      import org.osgi.framework.BundleContext;

      import org.osgi.framework.ServiceEvent;

      import org.osgi.framework.ServiceListener;

      public class HelloServiceConsumer implements BundleActivator {

      ??????//HelloService列表,有可能存在多个HelloService实现

      ???? //但我们优先使用最后注册的,达到服务更新的目的

      ?????? private List<HelloService> helloServices = new ArrayList<HelloService>();

      ?????? private ExecutorService executor;

      ?????? @Override

      ?????? public void start(BundleContext context) throws Exception {

      ????????????? System.out?.println(“HelloServiceConsumer.start”);

      ??????????? ?//添加服务监听器,监听HelloService的状态

      ????????????? context.addServiceListener(new HelloServiceListener(context));

      ????????????? executor = Executors.newFixedThreadPool?(1);

      ???????????? ?//线程里循环调用HelloService

      ????????????? executor.execute(new HelloServiceVisitorThread());

      ?????? }

      ?????? @Override

      ?????? public void stop(BundleContext context) throws Exception {

      ????????????? System.out?.println(“HelloServiceConsumer stop”);

      ?????? }

      ?????? public void setHelloService(HelloService helloService) {

      ????????????? if (this.helloServices.isEmpty()) {// 如果列表为空,直接加入

      ???????????????????? this.helloServices.add(helloService);

      ????????????? } else {// 将后启动的服务插入到列表之前,优先使用后加入的服务

      ???????????????????? this.helloServices.add(0, helloService);

      ????????????? }

      ?????? }

      ?????? public void unsetHelloService(HelloService helloService) {

      ????????????? //当HelloService卸载时,从服务列表删除

      ????????????? this.helloServices.remove(helloService);

      ?????? }

      ?????? class HelloServiceListener implements ServiceListener {

      ????????????? private BundleContext context;

      ????????????? public HelloServiceListener(BundleContext context) {

      ???????????????????? this.context = context;

      ????????????? }

      ????????????? @Override

      ????????????? public void serviceChanged(ServiceEvent evt) {

      ???????????????????? HelloService hs = (HelloService) context.getService(evt.getServiceReference());

      ???????????????????? if (evt.getType() == ServiceEvent.REGISTERED?) {

      ??????????????????????????? setHelloService(hs);//添加服务

      ???????????????????? } else if (evt.getType() == ServiceEvent.UNREGISTERING?) {

      ??????????????????????????? System.out?.println(“service unregistered”);

      ??????????????????????????? unsetHelloService(hs);//卸载服务

      ???????????????????? }

      ????????????? }

      ?????? }

      ?????? class HelloServiceVisitorThread implements Runnable {

      ????????????? public void run() {

      ???????????????????? while (true) {

      ??????????????????????????? try {

      ?????????????????????????????????? synchronized (helloServices) {

      ?????????????????????????????????? ?????? if (helloServices.size() > 0) {//判断是否有HelloService服务

      ???????????????????????????????????????????????? helloServices.get(0).sayHello();

      ????????????????????????????????????????? } else {

      ???????????????????????????????????????????????? System.out?.println(“NO HelloService”);

      ????????????????????????????????????????? }

      ?????????????????????????????????? }

      ?????????????????????????????????? TimeUnit.SECONDS?.sleep(20);

      ??????????????????????????? } catch (InterruptedException e) {

      ?????????????????????????????????? // ignore

      ??????????????????????????? }

      ???????????????????? }

      ????????????? }

      ?????? }

      }

      其MANIFEST.MF文件如下

      Manifest-Version: 1.0

      Created-By: Freewind

      Bundle-Version: 1.0.0

      Bundle-Name: Hello Service Consumer

      Bundle-Vendor: Freewind

      Bundle-ManifestVersion: 2

      Bundle-SymbolicName: hello.service.consumer

      Import-Package: org.osgi.framework,org.lazyman.osgi.hello.service

      Bundle-Activator: org.lazyman.osgi.hello.service.consumer.HelloServiceConsumer

      以上各工程的MANIFEST.MF文件放置布局如下:

      [zz]osgi 一碎步

      我们需要在打包时,将自定义的MANIFEST.MF打入jar包,只需要在主pom配置maven-jar-plugin即可

      ???????????????????? <plugin>

      ??????????????????????????? <groupId>org.apache.maven.plugins</groupId>

      ??????????????????????????? <artifactId>maven-jar-plugin</artifactId>

      ??????????????????????????? <configuration>

      ?????????????????????????????????? <archive>

      ????????????????????????????????????????? <manifestFile>META-INF/MANIFEST.MF</manifestFile>

      ?????????????????????????????????? </archive>

      ??????????????????????????? </configuration>

      ???????????????????? </plugin>

      打包各工程

      命令行进入主工程目录

      mvn clean package

      拷出各工程target下的jar到你喜欢的地方,比如c:/lib

      此处给个脚本,以方便拷出jar包—cp.bat

      copy /Y hello.service\target\hello.service.jar c:\lib

      copy /Y hello.service.consumer\target\hello.service.consumer.jar c:\lib

      copy /Y hello.service.impl1\target\hello.service.impl1.jar c:\lib

      copy /Y hello.service.impl2\target\hello.service.impl2.jar c:\lib

      启动osgi容器,此处使用equinox

      ?java -jar org.eclipse.osgi.jar –console?????????????????????[zz]osgi 一碎步

      ?此时只有一个bundle,也就是容器本身

      安装刚刚打包好的各个bundle

      install file:///c:/lib/hello.service.jar

      install file:///c:/lib/hello.service.impl1.jar

      install file:///c:/lib/hello.service.impl2.jar

      install file:///c:/lib/hello.service.consumer.jar

      安装的顺序可以随意,稍后启动的顺序必须先启动hello.service,因为后面三个对hello.service有依赖

      目前的状态如下

      [zz]osgi 一碎步

      可以看到有四个bundle处于已安装状态

      启动已安装的bundle

      上面提过,必须先启动hello.service,你也可以尝试下先启动其他bundle,看会有什么情况出现

      从上图可以看到,hello.service的id为2,此处的id相当于pid,我们可以用以下方式启动hello.service bundle

      start 2

      [zz]osgi 一碎步

      可以看到hello.service已经处于活动状态

      再启动hello.service.consumer,看看什么情况

      start 1?????

      [zz]osgi 一碎步

      有NO HelloService输出,因为此时还没有注册HelloService的实现

      启动实现1

      ?start 4

      [zz]osgi 一碎步?此后将一直输出HelloService1

      更新HelloService的实现,此时只需要启动实现2即可

      start 3

      [zz]osgi 一碎步

      此后HelloService将会切换到实现2上

      回滚到实现1上,只需要停止实现2即可

      ?stop 3

      ?[zz]osgi 一碎步

      此后HelloService将会回滚到实现1上

      你也可以编写实现3,并动态加载到osgi容器,替换实现1或实现2,为hello.service.consumer提供不一样的服务~~~

      equinox的osgi实现还有很多令人振奋的功能,比如声明式服务(ds),通过它以配置的方式注册或获取服务,可以省下很多繁琐的注册代码, 并且无需耦合osgi api,

热点排行