OSGI framework提供了一个osgi service registry,我们可以将一个java bean注册到这个osgi service registry上,然后,其它的bundle就可以通过osgi service registry来发现和引用这个Java bean,而这个Java bean就是一个OSGI Service(OSGI服务)了。
我们新建了一个demo2的示例代码,先看看demo2的代码结构:
其中:
3 是一个接口ICalculation,我们将它放在com.ponder.Demo.demo2.contract这个package下。
2 是ICalculation的一个实现。
1 是一个Activator,下面是它的代码:
package com.ponder.Demo.demo2;
import com.ponder.Demo.demo2.Impl.Calculation;
import com.ponder.Demo.demo2.contract.ICalculation;
import java.util.HashMap;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
/**
*
* @author han
*/
public class activator implements BundleActivator {
@Override
public void start(BundleContext context) throws Exception {
Dictionary<String, String> props = new Hashtable<String, String>();
props.put("ServiceName", "Calculation");
context.registerService(ICalculation.class.getName(), new Calculation(), props);
System.out.println("Service registered!");
}
@Override
public void stop(BundleContext context) throws Exception {
System.out.println("Stop demo2 bundle!");
}
}
代码中,我们定义了一个Hashtable(Dictionary的子类) props,这个称为“服务属性”,服务属性是一组键值对,每个服务都可以根据需要设置0到n个服务属性,服务属性的用处,我们后面会再介绍。
然后,我们用接口名、实现的实例(instance)和服务属性作为参数,通过BundleContext的registerService的方法将这个实现 注册到OSGI service registry上。
将项目编译打包成bundle后,部署到ServiceMix上:
通过list命令可以看到demo2的bundle ID是212,再用命令
可以看到demo2提供了一个osgi服务(服务接口为com.ponder.Demo.demo2.contract.ICalculation),服务ID为361,而且还列出了服务属性:ServiceName = Calculation
有了OSGI服务后,我们就可以在另一个Bundle引用它。
我们先看看demo3 activator的start方法:
@Override
public void start(BundleContext context) throws Exception {
ServiceReference[] refs = context.getServiceReferences(ICalculation.class.getName(), "(ServiceName=Calculation)");
if(refs!=null && refs.length>0){
ICalculation service=(ICalculation)context.getService(refs[0]);
System.out.println("1+1="+service.add(1, 1));
System.out.println("2-1="+service.sub(2, 1));
System.out.println("2*3="+service.sub(2, 3));
}
}
代码的第3行,通过Bundle Context的getServiceReferences方法获得实现服务接口ICalculation的服务引用,可能有多个。
这个方法有两个参数:
参数1是ICalculation的接口名(com.ponder.Demo.demo2.contract.ICalculation),这个和demo2注册服务时对应的服务接口是一致的;
参数2是一个表达式,它是和服务属性相关的,通过它,我们可以根据服务属性获得特定的OSGI服务,而不是所有实现该接口的OSGI服务;
注意
参数2可以如以下的形式:
"(ServiceName=Calculation)"
"&((ServiceName=Calculation)(ServiceType=Math))"
......
得到服务引用后,我们用Bundle Context的getService的方法得到其中的服务,并使用它。
在demo3里,我们就取用了第一个符合条件的服务;
在demo3的activator的代码里,我们import了demo2的com.ponder.Demo.demo2.contract.ICalculation这个接口类,而这个接口类是在demo2 bundle定义的,所以,如果不做处理,demo3是找不到这个类的。
所以,我们需要在demo2生成的bundle里面的META-INF/Mainifest.mf里将ICalculation所在的package(com.ponder.Demo.demo2.contract) export出来;然后在demo3生成的bundle里面的META-INF/Mainifest.mf里将这个package import进来。
我们是借助maven-jar-plugin,在pom.xml里分别指定:
demo2:留意第15行
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:pom="http://maven.apache.org/POM/4.0.0">
...
<build>
<plugins>
...
<plugin>
...
<artifactId>maven-jar-plugin</artifactId>
...
<configuration>
<archive>
...
<manifestEntries>
<Export-Package>com.ponder.Demo.demo2.contract;version="1.0"</Export-Package>
</manifestEntries>
</archive>
</configuration>
</plugin>
...
</plugins>
</build>
...
</project>
demo3:留意第15行
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:pom="http://maven.apache.org/POM/4.0.0">
...
<build>
<plugins>
...
<plugin>
...
<artifactId>maven-jar-plugin</artifactId>
...
<configuration>
<archive>
...
<manifestEntries>
<Import-Package>org.osgi.framework,com.ponder.Demo.demo2.contract;version="[1.0,2.0)"</Import-Package>
</manifestEntries>
</archive>
</configuration>
</plugin>
...
</plugins>
</build>
...
</project>
在打包时,maven就会在jar包里的META-INF/Mainifest.mf分别添加:
demo2:
demo3:
细心的同学或者会留意到demo2的Export-Package时,在package后加了一个版本号,而demo3的Import-Package则对package指定了一个版本号的区间[1.0,2.0)。这里表示的是demo3只Import版本号>=1.0,而且版本号<2.0的package。
我们尝试跑一下demo3,首先,我们先将
这时,我们只部署了demo2 bundle;通过ls
我们再将demo3-1.0.jar复制到
登录发表评论 登录 注册