OSGI实例demo说明(二)

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

这个demo包含五个Bundles:

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

BobSays、RodSays、KentSays三个Bundles分别实现了三个具体的sayHello();

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

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

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

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

在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 中的内容,用系统自动生成的就可以了。

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

SayHello 接口的代码如下:

package org.osgi.demo.say;

public interface SayHello {

	 public void sayHello();
}

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

创建新的类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 引入。

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

运行:

选择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 在具体执行的过程中行为是可动态改变的(根据启动不同实现动态指定让谁来说),并且改变只是局部的。

总结

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

时间: 2024-10-08 11:26:52

OSGI实例demo说明(二)的相关文章

ArcGIS API for JavaScript开发环境搭建及第一个实例demo

原文:ArcGIS API for JavaScript开发环境搭建及第一个实例demo ESRI公司截止到目前已经发布了最新的ArcGIS Server for JavaScript API v3.9,它提供了更为丰富而又强大的功能.     一.安装前准备 1.ArcGIS Server for JavaScript API各版本下载地址:http://support.esrichina-bj.cn/2011/0223/960.html,我们选择下载最新的"ArcGIS API for Ja

Spring aop 小实例demo

Hadoop从2.4.0版本开始支持hdfs的ACL,在CDH5.0当中也集成了该特性,下面对其进行一些测试: unnamed user (file owner) 文件的拥有者 unnamed group (file group) 文件的所属组 named user 除了文件的拥有者和拥有组之外,的其它用户 named group 除了文件的拥有者和拥有组之外,的其它用户 mask  权限掩码,用于过滤named user和named group的权限 一.启用ACL: <property>

Android之SlideMenu实例Demo

年末加班基本上一周都没什么时候回家写代码,回到家就想睡觉,周末难得有时间写个博客,上次写了一篇关于SlideMenu开源项目的导入问题,这次主要讲讲使用的问题,SlideMenu应用的广泛程度就不用说了,基本上是App的标配,关于SlideMenu的各种使用方法有很多,网上各种Demo也很多,想来想去还是按照自己本身的实战方式去写写吧,走过的坑希望大家基本上不会遇到,开始正题: 基础布局 写布局文件之前先看下最终的效果图,昨天红色就是滑动出现的区域,右边的图片由左边的事件触发: activity

Android ExpandableListView实例Demo

前几篇文章介绍了Listview,但在实际开发中也经常会用到多层的Listview来展示数据,比如qq中的好友展示,所以这张来了解一下ExpandableListview,基本思想与Listview大致是相同的,所以用起来会比较方便. 实现效果图: 程序代码: 布局文件: activity_main.xml: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools

Android ListFragment实例Demo(自定义适配器)

上一篇文章介绍了ListFragment,其中的ListView并没有自定义适配器,实际上在实际开发中常会用到自定义适配器,是实现更复杂的列表数据展示.所以这篇文章增加了自定义适配器,来进行ListView数据的展示. 实现效果图: 左边是Activity中的一个按钮,点击按钮会出现右边的Fragment相应的数据列表. 代码展示: 布局文件: activity_main: <LinearLayout xmlns:android="http://schemas.android.com/ap

Hadoop实例练习(二)

实例描述: 现有两个文件,dedu1.txt和dedu2.txt,数据文件中的每一行都是一个数据,现要对这两个文件进行去重,两个文件内容分别为(同颜色的表示重复的数据): dedu1.txt:                                            dedu2.txt: 2012-3-1 a                                                2012-3-1 b 2012-3-2 b                    

3 weekend110的hadoop中的RPC框架实现机制 + hadoop中的RPC应用实例demo

hadoop中的RPC框架实现机制 RPC是Remotr Process Call, 进程间的远程过程调用,不是在一个jvm里. 即,Controller拿不到Service的实例对象. hadoop中的RPC应用实例demo 在windows是调用端,在linux里是服务端. 在这里,需要LoginServiceinterface.java 停止 出错误了,很明显. 这是个很好的思考题?

Android ListFragment实例Demo

该篇文章是一个ListFragment的一个实例,通过了解该实例,更能了解比较常用的ListFragment的用法,以及各Fragment之间的数据传递. 实现效果图: 该MainActivity中包括1个Button+2个Fragment(右边两个),点击Button,出现中间的list列表,点击列表中的任一项,相应item数值,会传递到右边的Fragment中并显示. 源代码: activity_main: <LinearLayout xmlns:android="http://sch

Android微信分享功能实例+demo

Android微信分享功能实例 1 微信开放平台注册 2 获得appId,添加到程序中,并运行程序 3 使用应用签名apk生成签名,添加到微信开放平台应用签名,完成注册 4 测试分享功能. 有问题请留言  o(∩_∩)o 哈哈 代码如下: package com.wx; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.View; import a