(转)降低Eclipse RCP 项目 插件依赖度(OSGI 服务的理解)
?
下面这篇文章思路颇有点 osgi service 意思, 有思想的可以看看
?
上图中, org.talend.designer.core插件项目要依赖于如此多的其它项目。从整个系统的体系结构看,org.talend.designer.core对于红线连接的插件的依赖是不符合逻辑的。?另外,其他插件之间也存在着相互依赖的情况,例如Runprocess就要依赖于Repository。?随着以后插件项目的增多,这么复杂的依赖型将导致软件的维护越来越困难。?解决的方案是提供一个服务的注册,提供机制,所有的服务在一个地方统一注册,其他插件到这里取用。?以Repository模块为例:可以体现为如下设计方案。Repository作为服务的提供者,其他使用该功能的插件作为消费者。???实际实现1 在基础项目org.talend.core中提供统一的服务注册接口程序如下:?
package?org.talend.core;
import?java.util.HashMap;
import?java.util.Map;
import?org.eclipse.core.runtime.CoreException;
import?org.eclipse.core.runtime.IConfigurationElement;
import?org.eclipse.core.runtime.IExtensionRegistry;
import?org.eclipse.core.runtime.Platform;
import?org.talend.commons.exception.ExceptionHandler;
/**
?*?DOC?qian?class?global?comment.?A?global?service?register?provides?the?service?registration?and?acquirement.?<br/>
?*?
?*?$Id:?talend-code-templates.xml?1?2006-09-29?17:06:40?+0000?(星期五,?29?九月?2006)?nrousseau?$
?*?
?*/
public?class?GlobalServiceRegister?{
????//?The?shared?instance
????private?static?GlobalServiceRegister?instance?=?new?GlobalServiceRegister();
????private?static?IConfigurationElement[]?configurationElements;
????public?static?GlobalServiceRegister?getDefault()?{
????????return?instance;
????}
????private?Map<Class,?IService>?services?=?new?HashMap<Class,?IService>();
????static?{
????????IExtensionRegistry?registry?=?Platform.getExtensionRegistry();
????????configurationElements?=?registry.getConfigurationElementsFor("org.talend.core.service");
????}
????/**
?????*?DOC?qian?Comment?method?"getService".Gets?the?specific?IService.
?????*?
?????*?@param?klass?the?Service?type?you?want?to?get
?????*?@return?IService?IService
?????*/
????public?IService?getService(Class?klass)?{
????????IService?service?=?services.get(klass);
????????if?(service?==?null)?{
????????????service?=?findService(klass);
????????????if?(service?==?null)?{
????????????????throw?new?RuntimeException("The?service?"?+?klass.getName()?+?"?has?not?been?registered.");
????????????}
????????????services.put(klass,?service);
????????}
????????return?service;
????}
????/**
?????*?DOC?qian?Comment?method?"findService".Finds?the?specific?service?from?the?list.
?????*?
?????*?@param?klass?the?interface?type?want?to?find.
?????*?@return?IService
?????*/
????private?IService?findService(Class?klass)?{
????????String?key?=?klass.getName();
????????for?(int?i?=?0;?i?<?configurationElements.length;?i++)?{
????????????IConfigurationElement?element?=?configurationElements[i];
????????????String?id?=?element.getAttribute("serviceId");
????????????
????????????if?(!key.endsWith(id))?{
????????????????continue;
????????????}
????????????try?{
????????????????Object?service?=?element.createExecutableExtension("class");
????????????????if?(klass.isInstance(service))?{
????????????????????return?(IService)?service;
????????????????}
????????????}?catch?(CoreException?e)?{
????????????????ExceptionHandler.process(e);
????????????}
????????}
????????return?null;
????}
}??2 服务接口为:?
public?interface?IService?{
}3 插件扩展点定义为;org.talend.core/plugin.xml
<extension-point?id="service"?name="Service?Registration"?schema="schema/service.exsd"/>
4对于希望提供服务插件需要声明自己的服务类型。例如org.talend.repository插件希望提供服务。定义IRepositoryService.javapublic?interface?IRepositoryService?extends?IService?{
????public?IComponentsFactory?getComponentsFactory();
????public?IPath?getPathFileName(String?folderName,?String?fileName);
????
????public?IProxyRepositoryFactory?getProxyRepositoryFactory();
????
????public?IPath?getRepositoryPath(RepositoryNode?node);
}?
public?class?RepositoryService?implements?IRepositoryService?{
????public?IComponentsFactory?getComponentsFactory()?{
????????return?ComponentsFactoryProvider.getInstance();
????}
????public?IPath?getPathFileName(String?folderName,?String?fileName)?{
????????return?RepositoryPathProvider.getPathFileName(folderName,?fileName);
????}
????public?IProxyRepositoryFactory?getProxyRepositoryFactory()?{
????????return?ProxyRepositoryFactory.getInstance();
????}
????
????public?IPath?getRepositoryPath(RepositoryNode?node){
????????return?RepositoryNodeUtilities.getPath(node);
????}
}?5 org.talend.repository使用扩展点,使自己注册到org.talend.core中.org.talend.repository/plugin.xml
<extension
?????????point="org.talend.core.service">
??????<Service
????????????serviceId="IRepositoryService"
????????????class="org.talend.repository.RepositoryService"/>
?</extension>
??6 消费者使用org.talend.repository提供的服务时,只需要调用?
/**
?????*?DOC?get?a?implement?of?IRepositoryService.
?????*?
?????*?@return?a?implement?of?IRepositoryService
?????*/
????public?IRepositoryService?getRepositoryService()?{
????????IService?service?=?GlobalServiceRegister.getDefault().getService(IRepositoryService.class);
????????return?(IRepositoryService)?service;
????}?经过这样的改造,所有的插件都只要依赖org.talend.core即可,解决了插件间依赖结构混乱的问题。而且系统具有很好的开放性,很容易的加入其他服务的注册,有利于今后的扩展。?P.S. 一开始想利用Eclipse 的getAdaptable(Class) 机制来实现此功能,虽然也能实现,但是使用者还要自己写Facotry类,增加了扩展的难度,而且getAdaptable(Class)机制也不是用来解决这种问题的。而且自己控制服务的加载可以避免很多额外的麻烦。
?
我的异常网推荐解决方案:org.eclipse.core.runtime.CoreException,http://www.myexception.cn/eclipse/org.eclipse.core.runtime.CoreException.html