OSGi声明式服务是个好东西,有点依赖注入的味道,开发人员以配置的方式去注册或引用服务,你不需要为注册服务而单独写一个BundleActivator了,省去手工注册的繁琐。下面写一个例子改造上一篇代码的运行方式。
去掉HelloServiceConsumer对BundleActivator的实现,变成一个非常普通的java类,部分代码如下:
//引用被注入的服务
private HelloService helloService;
//当组件变为satisfied时,该方法将被调用
public void activate(ComponentContext context) {
executor = Executors.newFixedThreadPool (1);
executor.execute(new HelloServiceVisitorTask());
System.out .println(“HelloServiceConsumer activate”);
}
//当组件变为unsatisfied时,该方法将被调用
public void deactivate(ComponentContext context) {
executor.shutdownNow(); //关闭服务访问线程
executor = null ;
System.out .println(“HelloServiceConsumer deactivate”);
}
//当SCR(Service Component Runtime)发现容器中注册有HelloService服务时,该方法将被
//调用,相当于注入helloService实例,该方法在组件激活前调用
public void setHelloService(HelloService helloService) {
System.out .println(“setHelloService”);
synchronized (helloServiceLock) {
if (this .helloService != helloService) {
this .helloService = helloService;
}}}
//当提供HelloService服务的组件变为不可用时,该方法将被调用,相当解绑引用
public void unsetHelloService(HelloService helloService) {
synchronized (helloServiceLock) {
if (this.helloService == helloService) {
this.helloService = null;
}}}
在src/main/resources目录下建立OSGi-INF目录,用来存放组件描述xml文件,内容如下:
<?xml version=”1.0″ encoding=”UTF-8″?>
<component name=”HelloServiceConsumerComponent”>
<!– 该组件没有提供服务 –>
<implementationMsoNormal” align=”left” style=”text-align:left;mso-layout-grid-align: none;text-autospace:none”> <!– 引用服务 –>
<reference name=”HelloServiceComponent” interface=”org.lazyman.study.osgi.service.HelloService”
bind=”setHelloService” //绑定服务的方法
unbind=”unsetHelloService” //解绑服务的方法
//表示要求容器中存在HelloServiceComponent的个数,该参数影响组件的激活策略
cardinality=”0..1″
//在不调用deactivate情况重新绑定新的服务
policy=”dynamic” />
</component>
最后我们需要在MANIFEST.MF文件里增加新的头:
Service-Component: OSGi-INF/consumer.component.xml
去掉HelloServiceActivator类,增加hello.service.component.xml组件描述文件,内容如下
<?xml version=”1.0″ encoding=”UTF-8″?>
<component name=”HelloServiceComponent”>
<service>
// 表明提供org.lazyman.study.osgi.service.HelloService服务
<provide interface=”org.lazyman.study.osgi.service.HelloService” />
</service>
// 服务实现类
<implementation />
</component>
同样需要在MANIFEST.MF文件里增加新的头:
Service-Component: OSGi-INF/hello.service.component.xml
想激活基于服务的组件功能,需要增加如下bundle,可以去equinox网站下载
org.eclipse.equinox.ds //提供SCR功能
org.eclipse.equinox.util // ds的依赖
org.eclipse.osgi.services //osgi各种服务api
并且org.eclipse.equinox.ds bundle 必须在自定义bundle启动前启动,如下状态所示
Framework is launched.
id State Bundle
3 RESOLVED hello.service.consumer_1.0.0
4 RESOLVED hello.service.impl_1.0.0
5 RESOLVED hello.service_1.0.0
6 RESOLVED org.eclipse.equinox.ds_1.1.1.R35x_v20090806
7 <<LAZY>> org.eclipse.equinox.util_1.0.100.v20090520-1800
8 RESOLVED org.eclipse.osgi.services_3.2.0.v20090520-1800
启动 org.eclipse.equinox.ds bundle
start 6
id State Bundle
3 RESOLVED hello.service.consumer_1.0.0
4 RESOLVED hello.service.impl_1.0.0
5 RESOLVED hello.service_1.0.0
6 ACTIVE org.eclipse.equinox.ds_1.1.1.R35x_v20090806
7 ACTIVE org.eclipse.equinox.util_1.0.100.v20090520-1800
8 RESOLVED org.eclipse.osgi.services_3.2.0.v20090520-1800
分别启动5 4 3,可以看到如下结果
osgi> start 3
setHelloService //先调用服务绑定方法
HelloServiceConsumer activate //激活HelloServiceConsumerComponent
HelloService //调用服务接口方法的输出
该文总结了自己对OSGi声明式服务的学习历程,利用好这个功能可以让生活变得更加有趣!
目前启一个bundle都是手动start的,似乎有些麻烦,下篇将展示如何通过程序轻松启动所有bundle
–OSGi Declarative Services相关概念可以参见这篇文章(http://www.ibm.com/developerworks/cn/opensource/os-ecl-osgids/index.html )