OSGI实例demo说明(二)

下面我们就来真正的写一个实例demo,结合OSGI的优点来说明一下,该demo设计如下图:

         OSGI实例demo说明(二)_第1张图片

这个demo包含五个Bundles

SayHello Bundle 包含一个接口,只有唯一的方法sayHello();

BobSaysRodSaysKentSays三个Bundles分别实现了三个具体的sayHello()

SayHelloServiceBundle提供了说hello的机会,是具体的一个服务应用,在功能上有点类似于main函数的味道。

 

这个HelloWorlddemo 的目的不但可以让读者小试牛刀,而且可以同时体会一下OSGi 最大的优点——服务状态的可更改性。

BobSays、RodSays、KentSays 实现了SayHello 暴露的接口,它们是sayHello 的具体执行者,但是在SayHelloService 调用的过程中,我们可以动态的改变到底是谁(BobSays、RodSays、KentSays)来说。

为了实现这个demo,还需要简单介绍一下OSGi 最简单的实现机制:OSGiBundles 之间包的依赖关系。每一个OSGi Bundle 的类文件可分为私有的、引入的、暴露的三种,如下图所示

              OSGI实例demo说明(二)_第2张图片

在OSGi 中ExportedClasses 是以包的方式暴露的,如图所示,SayHello 中暴露了接口所在的包,对应的BobSays等三个Bundles 和SayHelloService Bundle 都引入了该包,这是OSGi 中最简单的通信方式,OSGi 规范中推荐使用面向服务的通信方式,这里只是举一个简单的实例,因此不用做的那么复杂。

 

实战开始: 

新建一个名为SayHello 的plug-inproject,在Target Platform 选项中,选择an OSGi Framework:Equinox。我们自己设置了Activator路径为org.osgi.demo.sayHello.Activator,每个Activator 都具有两个方法,start()和stop(),这两个方法是该bundle 启动、停止的时候,调用的方法,通常在这里注册、初始化或注销该Bundle 服务的过程,这里不需要更改任何Activator 中的内容,用系统自动生成的就可以了。


           OSGI实例demo说明(二)_第3张图片


在建立好项目后,会出现对SayHello项目的配置,这里可以通过dependencies 选项卡,设置需要的plug-in 和引入的package;可以通过runtime 选项卡的设置,确定暴露哪些包。我们新建一个org.osgi.demo.say 包,并建立SayHello 接口,只有一个返回void的方法sayHello() ,并将此包设为暴露的(通过这种暴露方式实现了信息隐藏)。这些设置都保存在项目的META-INF目录下的MANIFEST.MF文件中,以后要更改的话,只需打开该文件即可。


        OSGI实例demo说明(二)_第4张图片

SayHello 接口的代码如下:

package org.osgi.demo.say;

public interface SayHello {
	
	 public void sayHello();
}

同样类似的新建一个名为BobSays的plug-inproject。设置的包为org.osgi.demo.bob,这里需要在配置dependencies 的时候,将包org.osgi.demo.say 引入。


           OSGI实例demo说明(二)_第5张图片

     OSGI实例demo说明(二)_第6张图片


创建新的类BobSays,代码如下:

package org.osgi.demo.bob;

import org.osgi.demo.say.SayHello;

public class BobSays implements SayHello {
    public void sayHello() {
        System.out.println("Bob says \"Hello OSGi world\"");
    }
}

这里需要覆写在BobSaysBundle 中的Activator 的两个方法,具体代码如下:

package org.osgi.demo.bobsays;

import org.osgi.demo.bob.BobSays;
import org.osgi.demo.say.SayHello;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;

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-inproject。设置的包为org.osgi.demo.service,同样在配置dependencies 的时候,将包org.osgi.demo.say 引入。


           OSGI实例demo说明(二)_第7张图片

      OSGI实例demo说明(二)_第8张图片


创建SayHelloService类,代码如下:

package org.osgi.demo.service;

import org.osgi.demo.say.SayHello;

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 代码如下:

package org.osgi.demo.sayhelloservice;

import org.osgi.demo.say.SayHello;
import org.osgi.demo.service.SayHelloService;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;

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服务中,现在注入的服务是从服务上下文中具体获取的,而到底是哪个,只有在运行时状态才能决定。


运行:

               

  OSGI实例demo说明(二)_第9张图片


选择Open Run Dialog...,并选中上述3个Bundles 和OSGi 核心Bundle,点击Run 按钮。输入“ss”,列出了3个Bundles 的状态(在这里我只建立了BobSays),此时,如果你的SayHelloService Bundle 状态是Resolved,那么你可以通过命令“start ‘SayHelloServiceBundle 状态的id’”,启动SayHelloService,此时你会看到打印出的10条hello world信息。读者可以手动利用用命令“start” 和“stop” 改变sayHello 的具体执行者,动态的更换实际sayHello 的执行者。这个简单的HelloWorld 应用,可以说明SayHelloService 在具体执行的过程中行为是可动态改变的(根据启动不同实现动态指定让谁来说),并且改变只是局部的。


               OSGI实例demo说明(二)_第10张图片

总结

通过以上简单的实例demo,相信大家已经能理解前文所说的OSGI架构的一些模块化特征,这个demo只是一个基础,在学习的初期一个入门实例,由于OSGi 字面上的意思太过于抽象,我们在学习的时候还是要结合实例去理解比较容易。




你可能感兴趣的:(JAVA)