Equinox项目是 Eclipse开源组织提供的OSGi框架的实现。Equinox 的org.eclipse.equinox.ds项目提供了OSGi R4规范中的Declarative Service标准服务的实现。Declarative Service提供了基于OSGI平台之上的面向服务构件模型(Service-Oriented Component Model),也为在OSGI基础之上搭建 SOA应用提供了可能。 背景信息
Equinox项目是 Eclipse开源组织提供的OSGi框架的实现。 Eclipse自3.0版本开始,其内核移植到OSGi框架上。通过OSGi框架强大的组件控制,交互和管理能力,再加上 Eclipse插件的自有特点, Eclipse开源框架得到了跳跃式的发展。同时,OSGi规范得益于 Eclipse IDE环境庞大的使用者,OSGi联盟也进入了快速发展时期。
Equinox项目概述
Equinox项目包括OSGi R4版本规范核心框架的实现,一系列OSGi标准服务Bundle及运行基于OSGi的系统的一些基础构件。目前,Equinox项目包括OSGi核心框架的实现,OSGi标准服务Bundle实现,OSGi的服务器端(J2EE实现)应用,Equinox部署更新框架及一些研究方向(未成熟发布的构想如JMX管理,安全管理,面向方面的设计与应用等)。
Equinox Declarative Services(DS)
Equinox 的org.eclipse.equinox.ds项目提供了OSGi R4规范中的Declarative Service标准服务的实现,该组件由Prosyst公司提供实现。Declarative Service提供了基于OSGI平台之上的面向服务构件模型(Service-Oriented Component Model),也为在OSGI基础之上搭建 SOA应用提供了可能。Declarative Service实现并没有包含在 Eclipse的默认软件包中,需要从 Eclipse的CVS中获取。代码位于:pserver:anonymous:dev.eclipse.org/cvsroot/eclipse路径下。
Equinox在没有DS实现之前,对于服务的注册需要手工来做,如下面的代码:
|
service = new HelloServiceImpl();
// register the service
context.registerService(HelloService.class.getName(), service, new Hashtable());
// create a tracker and track the service
helloServiceTracker = new ServiceTracker(context, HelloService.class.getName(), null);
helloServiceTracker.open();
// grab the service
service = (HelloService) helloServiceTracker.getService();
service.speak();
|
在提供了DS之后可以采用XML文件的方式来声明:
上面的XML文件声明了HelloService的构件,实现类是com.primeton.osgi.HelloServiceImpl,同时,声明了构件的服务接口为com.primeton.osgi.HelloService。如果不声明服务,当你使用类似下面的代码是查找不到服务的:
|
ServiceReference reference = context.getServiceReference(TestService.class.getName());
TestService service = (TestService)context.getService(reference);
service.test();
|
调用BundleContext的getServiceReference方法将返回空。
类似于SCA规范的构件装配模型,Component可以引用别的Component的服务。如我们声明一个TestService,TestService引用了HelloService。
是不是和 SCA的装配模型描述文件有点相似呢?^_^
下面对Equinox的Declarative Service的实现进行一下分析。
加载ComponentDescriptor
首先,构件的描述文件是如何被加载的呢?加载由org.eclipse.equinox.ds.tracker.BundleTracker来实现。BundleTracker会遍历所有的Bundle处于ACTIVE状态的Bundle,BundleTracker回调BundleTrackerCustomizer的addingBundle方法,读取所有的ComponentDescriptor,并加入到异步工作队列WorkQueue中。
Resovle ComponentDescriptor
加入到异步队列中的ComponentDescriptor需要由org.eclipse.equinox.ds.resolver. Resolver进行解析,判断Component所依赖的服务构件是否都存在,并满足条件。然后创建ComponentConfiguration。
解析Manifest Header
org.eclipse.equinox.ds.parser.Parser会解析Manifest文件,读取Manifest文件中的Service-Component属性。代码如下:
|
private ManifestElement[] parseManifestHeader(Bundle bundle) {
Dictionary headers = bundle.getHeaders();
String files = (String) headers.get(ComponentConstants.SERVICE_COMPONENT);
try {
return ManifestElement.parseHeader(ComponentConstants.SERVICE_COMPONENT, files);
} catch (BundleException e) {
Log.log(1, "[SCR] Error attempting parse Manifest Element Header. ", e);
returnnew ManifestElement[0];
}
}
|
因此,为了使Component的描述文件被加载,必须在Manifest文件中申明要加载的xml文件。如下所示:
|
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Test Plug-in
Bundle-SymbolicName: test
Bundle-Version: 1.0.0
Service-Componen: test.xml
Import-Package: org.osgi.framework;version="1.3.0",
org.osgi.util.tracker;version="1.3.1"
|
解析ComponentDescriptor
org.eclipse.equinox.ds.parser.Parser同时会负责解析构件描述文件。
创建Component实例
org.eclipse.equinox.ds.instance.BuildDispose负责根据ComponentDescriptor创建Component的实例。具体参见buildComponentConfigInstance方法。
|
ComponentDescription componentDescription = componentConfiguration.getComponentDescription();
Object instance = createInstance(componentDescription);
componentInstance = instantiate(componentConfiguration, instance);
createComponentContext(usingBundle, componentInstance);
bind(componentInstance);
activate(componentInstance);
componentConfiguration.addInstance(componentInstance);
|
1. 首先从ComponentConfiguration中获取ComponentDescriptor.
2. 根据ComponentDescritptor创建一个Component的实例。
3. 创建Component的上下文ComponentContext。
4. 将Component需要的Service进行绑定。
5. 调用Component的activate方法,激活Component。
Component可以是任何一个Java类,而不需要继承或实现OSGI的类或接口,但可以定义一个activate方法,在Component被激活时作相关处理。
org.eclipse.equinox.ds.instance.InvokeMethod负责在调用Component的相关方法,采用类反射的机制将Server绑定到Component上。InvokeMethod的findBindOrUnbindMethod会在Component的实现类和超类中去查找绑定方法。
从以上分析,可以看出Equinox的Declarative Service实现了一个服务构件定义、加载、装配、服务查找的一个服务构件运行环境。和SCA的构件装配模型异曲同工。Declarative Service规范应该早于SCA规范的制定,因此,在某种程度上,SCA装配模型参考了Declarative Service的服务构件模型,并在此基础上发展完善,多出了Contribution、Composite等概念,对于服务绑定的范畴也进行了拓宽,并不局限于Java语言的Service,从而做到了语言无关、平台无关。
|