降低Eclipse RCP 项目 插件依赖度

Talend产品中,模块之间的依赖都是给予代码直接访问,每个插件项目没有自身的使用规则。造成插件间的混乱无序依赖。参见大型RCP项目,降低插件依赖度

例如:
降低Eclipse RCP 项目 插件依赖度
上图中, org.talend.designer.core插件项目要依赖于如此多的其它项目。
从整个系统的体系结构看,org.talend.designer.core对于红线连接的插件的依赖是不符合逻辑的。
另外,其他插件之间也存在着相互依赖的情况,例如Runprocess就要依赖于Repository。
随着以后插件项目的增多,这么复杂的依赖型将导致软件的维护越来越困难。
解决的方案是提供一个服务的注册,提供机制,所有的服务在一个地方统一注册,其他插件到这里取用。
以Repository模块为例:可以体现为如下设计方案。
Repository作为服务的提供者,其他使用该功能的插件作为消费者。
降低Eclipse RCP 项目 插件依赖度
实际实现
1 在基础项目org.talend.core中提供统一的服务注册接口程序如下:
降低Eclipse RCP 项目 插件依赖度packageorg.talend.core;
降低Eclipse RCP 项目 插件依赖度
降低Eclipse RCP 项目 插件依赖度
importjava.util.HashMap;
降低Eclipse RCP 项目 插件依赖度
importjava.util.Map;
降低Eclipse RCP 项目 插件依赖度
降低Eclipse RCP 项目 插件依赖度
importorg.eclipse.core.runtime.CoreException;
降低Eclipse RCP 项目 插件依赖度
importorg.eclipse.core.runtime.IConfigurationElement;
降低Eclipse RCP 项目 插件依赖度
importorg.eclipse.core.runtime.IExtensionRegistry;
降低Eclipse RCP 项目 插件依赖度
importorg.eclipse.core.runtime.Platform;
降低Eclipse RCP 项目 插件依赖度
importorg.talend.commons.exception.ExceptionHandler;
降低Eclipse RCP 项目 插件依赖度
降低Eclipse RCP 项目 插件依赖度降低Eclipse RCP 项目 插件依赖度
/***//**
降低Eclipse RCP 项目 插件依赖度*DOCqianclassglobalcomment.Aglobalserviceregisterprovidestheserviceregistrationandacquirement.<br/>
降低Eclipse RCP 项目 插件依赖度*
降低Eclipse RCP 项目 插件依赖度*$Id:talend-code-templates.xml12006-09-2917:06:40+0000(星期五,29九月2006)nrousseau$
降低Eclipse RCP 项目 插件依赖度*
降低Eclipse RCP 项目 插件依赖度
*/

降低Eclipse RCP 项目 插件依赖度降低Eclipse RCP 项目 插件依赖度
publicclassGlobalServiceRegister...{
降低Eclipse RCP 项目 插件依赖度
降低Eclipse RCP 项目 插件依赖度
//Thesharedinstance
降低Eclipse RCP 项目 插件依赖度
privatestaticGlobalServiceRegisterinstance=newGlobalServiceRegister();
降低Eclipse RCP 项目 插件依赖度
降低Eclipse RCP 项目 插件依赖度
privatestaticIConfigurationElement[]configurationElements;
降低Eclipse RCP 项目 插件依赖度
降低Eclipse RCP 项目 插件依赖度降低Eclipse RCP 项目 插件依赖度
publicstaticGlobalServiceRegistergetDefault()...{
降低Eclipse RCP 项目 插件依赖度
returninstance;
降低Eclipse RCP 项目 插件依赖度}

降低Eclipse RCP 项目 插件依赖度
降低Eclipse RCP 项目 插件依赖度
privateMap<Class,IService>services=newHashMap<Class,IService>();
降低Eclipse RCP 项目 插件依赖度
降低Eclipse RCP 项目 插件依赖度降低Eclipse RCP 项目 插件依赖度
static...{
降低Eclipse RCP 项目 插件依赖度IExtensionRegistryregistry
=Platform.getExtensionRegistry();
降低Eclipse RCP 项目 插件依赖度configurationElements
=registry.getConfigurationElementsFor("org.talend.core.service");
降低Eclipse RCP 项目 插件依赖度}

降低Eclipse RCP 项目 插件依赖度
降低Eclipse RCP 项目 插件依赖度降低Eclipse RCP 项目 插件依赖度
/***//**
降低Eclipse RCP 项目 插件依赖度*DOCqianCommentmethod"getService".GetsthespecificIService.
降低Eclipse RCP 项目 插件依赖度*
降低Eclipse RCP 项目 插件依赖度*
@paramklasstheServicetypeyouwanttoget
降低Eclipse RCP 项目 插件依赖度*
@returnIServiceIService
降低Eclipse RCP 项目 插件依赖度
*/

降低Eclipse RCP 项目 插件依赖度降低Eclipse RCP 项目 插件依赖度
publicIServicegetService(Classklass)...{
降低Eclipse RCP 项目 插件依赖度IServiceservice
=services.get(klass);
降低Eclipse RCP 项目 插件依赖度降低Eclipse RCP 项目 插件依赖度
if(service==null)...{
降低Eclipse RCP 项目 插件依赖度service
=findService(klass);
降低Eclipse RCP 项目 插件依赖度降低Eclipse RCP 项目 插件依赖度
if(service==null)...{
降低Eclipse RCP 项目 插件依赖度
thrownewRuntimeException("Theservice"+klass.getName()+"hasnotbeenregistered.");
降低Eclipse RCP 项目 插件依赖度}

降低Eclipse RCP 项目 插件依赖度services.put(klass,service);
降低Eclipse RCP 项目 插件依赖度}

降低Eclipse RCP 项目 插件依赖度
returnservice;
降低Eclipse RCP 项目 插件依赖度}

降低Eclipse RCP 项目 插件依赖度
降低Eclipse RCP 项目 插件依赖度降低Eclipse RCP 项目 插件依赖度
/***//**
降低Eclipse RCP 项目 插件依赖度*DOCqianCommentmethod"findService".Findsthespecificservicefromthelist.
降低Eclipse RCP 项目 插件依赖度*
降低Eclipse RCP 项目 插件依赖度*
@paramklasstheinterfacetypewanttofind.
降低Eclipse RCP 项目 插件依赖度*
@returnIService
降低Eclipse RCP 项目 插件依赖度
*/

降低Eclipse RCP 项目 插件依赖度降低Eclipse RCP 项目 插件依赖度
privateIServicefindService(Classklass)...{
降低Eclipse RCP 项目 插件依赖度Stringkey
=klass.getName();
降低Eclipse RCP 项目 插件依赖度降低Eclipse RCP 项目 插件依赖度
for(inti=0;i<configurationElements.length;i++)...{
降低Eclipse RCP 项目 插件依赖度IConfigurationElementelement
=configurationElements[i];
降低Eclipse RCP 项目 插件依赖度Stringid
=element.getAttribute("serviceId");
降低Eclipse RCP 项目 插件依赖度
降低Eclipse RCP 项目 插件依赖度降低Eclipse RCP 项目 插件依赖度
if(!key.endsWith(id))...{
降低Eclipse RCP 项目 插件依赖度
continue;
降低Eclipse RCP 项目 插件依赖度}

降低Eclipse RCP 项目 插件依赖度降低Eclipse RCP 项目 插件依赖度
try...{
降低Eclipse RCP 项目 插件依赖度Objectservice
=element.createExecutableExtension("class");
降低Eclipse RCP 项目 插件依赖度降低Eclipse RCP 项目 插件依赖度
if(klass.isInstance(service))...{
降低Eclipse RCP 项目 插件依赖度
return(IService)service;
降低Eclipse RCP 项目 插件依赖度}

降低Eclipse RCP 项目 插件依赖度降低Eclipse RCP 项目 插件依赖度}
catch(CoreExceptione)...{
降低Eclipse RCP 项目 插件依赖度ExceptionHandler.process(e);
降低Eclipse RCP 项目 插件依赖度}

降低Eclipse RCP 项目 插件依赖度}

降低Eclipse RCP 项目 插件依赖度
returnnull;
降低Eclipse RCP 项目 插件依赖度}

降低Eclipse RCP 项目 插件依赖度}
2 服务接口为:
降低Eclipse RCP 项目 插件依赖度降低Eclipse RCP 项目 插件依赖度publicinterfaceIService...{
降低Eclipse RCP 项目 插件依赖度
降低Eclipse RCP 项目 插件依赖度}
3 插件扩展点定义为;
org.talend.core/plugin.xml
降低Eclipse RCP 项目 插件依赖度<extension-pointid="service"name="ServiceRegistration"schema="schema/service.exsd"/>
降低Eclipse RCP 项目 插件依赖度
4对于希望提供服务插件需要声明自己的服务类型。
例如org.talend.repository插件希望提供服务。
定义IRepositoryService.java 此类放入org.talend.core中。
在org.talend.repository实现IrepositoryService
降低Eclipse RCP 项目 插件依赖度降低Eclipse RCP 项目 插件依赖度publicinterfaceIRepositoryServiceextendsIService...{
降低Eclipse RCP 项目 插件依赖度
降低Eclipse RCP 项目 插件依赖度
publicIComponentsFactorygetComponentsFactory();
降低Eclipse RCP 项目 插件依赖度
降低Eclipse RCP 项目 插件依赖度
publicIPathgetPathFileName(StringfolderName,StringfileName);
降低Eclipse RCP 项目 插件依赖度
降低Eclipse RCP 项目 插件依赖度
publicIProxyRepositoryFactorygetProxyRepositoryFactory();
降低Eclipse RCP 项目 插件依赖度
降低Eclipse RCP 项目 插件依赖度
publicIPathgetRepositoryPath(RepositoryNodenode);
降低Eclipse RCP 项目 插件依赖度}
降低Eclipse RCP 项目 插件依赖度降低Eclipse RCP 项目 插件依赖度publicclassRepositoryServiceimplementsIRepositoryService...{
降低Eclipse RCP 项目 插件依赖度
降低Eclipse RCP 项目 插件依赖度降低Eclipse RCP 项目 插件依赖度
publicIComponentsFactorygetComponentsFactory()...{
降低Eclipse RCP 项目 插件依赖度
returnComponentsFactoryProvider.getInstance();
降低Eclipse RCP 项目 插件依赖度}

降低Eclipse RCP 项目 插件依赖度
降低Eclipse RCP 项目 插件依赖度降低Eclipse RCP 项目 插件依赖度
publicIPathgetPathFileName(StringfolderName,StringfileName)...{
降低Eclipse RCP 项目 插件依赖度
returnRepositoryPathProvider.getPathFileName(folderName,fileName);
降低Eclipse RCP 项目 插件依赖度}

降低Eclipse RCP 项目 插件依赖度
降低Eclipse RCP 项目 插件依赖度降低Eclipse RCP 项目 插件依赖度
publicIProxyRepositoryFactorygetProxyRepositoryFactory()...{
降低Eclipse RCP 项目 插件依赖度
returnProxyRepositoryFactory.getInstance();
降低Eclipse RCP 项目 插件依赖度}

降低Eclipse RCP 项目 插件依赖度
降低Eclipse RCP 项目 插件依赖度降低Eclipse RCP 项目 插件依赖度
publicIPathgetRepositoryPath(RepositoryNodenode)...{
降低Eclipse RCP 项目 插件依赖度
returnRepositoryNodeUtilities.getPath(node);
降低Eclipse RCP 项目 插件依赖度}

降低Eclipse RCP 项目 插件依赖度}
5 org.talend.repository使用扩展点,使自己注册到org.talend.core中.
org.talend.repository/plugin.xml
降低Eclipse RCP 项目 插件依赖度<extension
降低Eclipse RCP 项目 插件依赖度
point="org.talend.core.service">
降低Eclipse RCP 项目 插件依赖度
<Service
降低Eclipse RCP 项目 插件依赖度
serviceId="IRepositoryService"
降低Eclipse RCP 项目 插件依赖度class
="org.talend.repository.RepositoryService"/>
降低Eclipse RCP 项目 插件依赖度
</extension>
降低Eclipse RCP 项目 插件依赖度
6 消费者使用org.talend.repository提供的服务时,只需要调用
降低Eclipse RCP 项目 插件依赖度降低Eclipse RCP 项目 插件依赖度/***//**
降低Eclipse RCP 项目 插件依赖度*DOCgetaimplementofIRepositoryService.
降低Eclipse RCP 项目 插件依赖度*
降低Eclipse RCP 项目 插件依赖度*
@returnaimplementofIRepositoryService
降低Eclipse RCP 项目 插件依赖度
*/

降低Eclipse RCP 项目 插件依赖度降低Eclipse RCP 项目 插件依赖度
publicIRepositoryServicegetRepositoryService()...{
降低Eclipse RCP 项目 插件依赖度IServiceservice
=GlobalServiceRegister.getDefault().getService(IRepositoryService.class);
降低Eclipse RCP 项目 插件依赖度
return(IRepositoryService)service;
降低Eclipse RCP 项目 插件依赖度}
经过这样的改造,所有的插件都只要依赖org.talend.core即可,解决了插件间依赖结构混乱的问题。而且系统具有很好的开放性,很容易的加入其他服务的注册,有利于今后的扩展。
P.S. 一开始想利用Eclipse 的getAdaptable(Class) 机制来实现此功能,虽然也能实现,但是使用者还要自己写Facotry类,增加了扩展的难度,而且getAdaptable(Class)机制也不是用来解决这种问题的。而且自己控制服务的加载可以避免很多额外的麻烦。