如果两个插件出现双向的独立性关联就形成了循环依赖,Dengues利用Eclipse扩展点方式解决这个问题。

        首先来介绍一下原理。Eclipse在启动的时候会将所有的扩展点实现加载到一个注册表里面,这里注册的东西可以是一个类,就像是我们通过扩展点的方式实现一个Viewer一样,我们不仅要写入相应的icon还要写入相关的指定的类。
            

            
        同样道理,如果我们可以定义一个扩展点,在Eclipse启动的时候把实现了这个扩展点的类加载到一个核心插件里。如果别的插件如果要用这个类的话,直接加入对之个核心插件的依赖不就可以了从而回避了对这个插件直接的依赖见下图:

        
        在图1里A插件要引用B插件里的类,同样B插件也有需求要引用A插件里的类,这样就造成了插件的循环依赖。现在利用扩展点,在A,B插件里实现一个定义于Core插件里的扩展点,在Eclispe启动的时候,实现了此扩展点的类将可以被加载到Core插件里。通过Core的桥梁作用A、B插件便可以实现类的相互引用。这里A、B插件只是对Core有一个单向的依赖关系,通过core插件的帮助A与B之间可以相互调,避免了直接的调用所以也就不会形成循环依赖了。

        一、扩展点的定义:

        点击进入org.dengues.core插件的plugin.xml 文件,打开Extension Point标签,点Add加入一个扩展点输入如下信息:
        
        在Definition里加一个叫做Service的element,并加入两条use栏为reuqired的属性如下图所示:

        

        其中serviceClass的Type要选成java,并且在Implements里定义一个接口,这个接口规定了这个扩展点在实现的时候指定的类。这里为IDenguesService。其实接口里什么也没方法也没有定义,只是一个申明而已。
        

        

package org.dengues.core;

public interface IDenguesService {

    String ID 
= "org.dengues.commons.denguesService"//$NON-NLS-1$

    String SERVICE_CLASS 
= "serviceClass"//$NON-NLS-1$

    String SERVICE_ID 
= "serviceID"//$NON-NLS-1$
}


        
        二、实现扩展点。具体怎么用一个扩展点,这里就不用多说了,只重点介绍一下怎么实现IDenguesService类。我们以Dengues里的org.dengues.design.core插件为例。在org.dengues.core里我们我建一个IDenguesService的子接口IDesignerCoreService,并写入我们要向其它plugin公开的方法。
        

public interface IDesignerCoreService extends IDenguesService {

    
public IComponentsFactory getComponentsFactory();

    
public IComponentFilesNaming getComponentFilesNaming();

    
public void initializeTemplates();

    
public ICodeGenerator getCodeGenerator(ICompProcess process);

    
public ICodeGenerator getCodeGenerator();

    
public IJavaETLProcessor getJavaProcessor(ICompProcess process);

    
public IJavaETLProcessor getJavaProcessor();

    
// public Action createStartHsqldbServer(String dbName);

    
public Action createStartHsqldbServer();

    
public boolean checkHsqldbConnection();

    
public void runSqlScript(IFile scriptFile);

    
public DatabaseContainer getHsqlDatabase() throws SQLException;

    
public Connection getCurrentConnection() throws SQLException, CoreException, ClassNotFoundException;
}


         以上这些方法就是org.dengues.designer.core这个插件想要对其它插件公开的方法了,它的实现自然会被写入到这个插件里了。这段代码很多,我们就不列在这里了,如果有兴趣的朋友可以到我们Dengues的google svn去check out代码。写好对IDesignerCoreService的实现以后,我们就可以把它加入到事先我们定义好的扩展点里了,见下图:
        
        

        图中的DesignerCoreService就是IDesingerCoreService的实现。好了,当Eclipse启动的时候它就会把这个类加载到注册表里了,我们可以从这个注册里取到这个类了。那以后如果我们想从这个plugin里向外公开一些方法的话,就可以通过向IDesignerCoreService写入相应的方法,在DesignerCoreService里写入相应的实现就可以了。

        三、从注册表里取出扩展点的类。

        在org.dengues.core里我们写了一个GlobalServiceFactory里面提供了相应的代码:

            

static {
        IExtensionRegistry registry 
= Platform.getExtensionRegistry();
        configurationElements 
= registry.getConfigurationElementsFor(IDenguesService.ID); //$NON-NLS-1$
    }


    
/**
     * Comment method "getService".Gets the specific IService.
     * 
     * 
@param klass the Service type you want to get
     * 
@return IService IService
     
*/

    
public IDenguesService getService(Class klass) {
        IDenguesService service 
= services.get(klass);
        
if (service == null{
            service 
= findService(klass);
            
if (service == null{
                
throw new RuntimeException("GlobalServiceRegister.ServiceNotRegistered" + klass.getName()); //$NON-NLS-1$
            }

            services.put(klass, service);
        }

        
return service;
    }


        如果我们要取刚才定义好的那个IDesignerCoreService的话,我们可以按如下方式取到:

    public IDesignerCoreService getDesignerCoreService() {
        IDenguesService service 
= GlobalServiceFactory.getDefault().getService(IDesignerCoreService.class);
        
return (IDesignerCoreService) service;
    }

        
        其实段代码是写在org.dengues.core插件里的CorePlugin里的,也就是说在任何一个插件里只要加入了对org.dengues.core的依赖都可以通过CorePlguin.getDefault().getDesignerCoreService()来得到IDesignerCoreService的实例了。