如果兩個插件出現(xiàn)雙向的獨立性關(guān)聯(lián)就形成了循環(huán)依賴,Dengues利用Eclipse擴展點方式解決這個問題。

        首先來介紹一下原理。Eclipse在啟動的時候會將所有的擴展點實現(xiàn)加載到一個注冊表里面,這里注冊的東西可以是一個類,就像是我們通過擴展點的方式實現(xiàn)一個Viewer一樣,我們不僅要寫入相應(yīng)的icon還要寫入相關(guān)的指定的類。
            

            
        同樣道理,如果我們可以定義一個擴展點,在Eclipse啟動的時候把實現(xiàn)了這個擴展點的類加載到一個核心插件里。如果別的插件如果要用這個類的話,直接加入對之個核心插件的依賴不就可以了從而回避了對這個插件直接的依賴見下圖:

        
        在圖1里A插件要引用B插件里的類,同樣B插件也有需求要引用A插件里的類,這樣就造成了插件的循環(huán)依賴。現(xiàn)在利用擴展點,在A,B插件里實現(xiàn)一個定義于Core插件里的擴展點,在Eclispe啟動的時候,實現(xiàn)了此擴展點的類將可以被加載到Core插件里。通過Core的橋梁作用A、B插件便可以實現(xiàn)類的相互引用。這里A、B插件只是對Core有一個單向的依賴關(guān)系,通過core插件的幫助A與B之間可以相互調(diào),避免了直接的調(diào)用所以也就不會形成循環(huán)依賴了。

        一、擴展點的定義:

        點擊進入org.dengues.core插件的plugin.xml 文件,打開Extension Point標簽,點Add加入一個擴展點輸入如下信息:
        
        在Definition里加一個叫做Service的element,并加入兩條use欄為reuqired的屬性如下圖所示:

        

        其中serviceClass的Type要選成java,并且在Implements里定義一個接口,這個接口規(guī)定了這個擴展點在實現(xiàn)的時候指定的類。這里為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$
}


        
        二、實現(xiàn)擴展點。具體怎么用一個擴展點,這里就不用多說了,只重點介紹一下怎么實現(xiàn)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這個插件想要對其它插件公開的方法了,它的實現(xiàn)自然會被寫入到這個插件里了。這段代碼很多,我們就不列在這里了,如果有興趣的朋友可以到我們Dengues的google svn去check out代碼。寫好對IDesignerCoreService的實現(xiàn)以后,我們就可以把它加入到事先我們定義好的擴展點里了,見下圖:
        
        

        圖中的DesignerCoreService就是IDesingerCoreService的實現(xiàn)。好了,當Eclipse啟動的時候它就會把這個類加載到注冊表里了,我們可以從這個注冊里取到這個類了。那以后如果我們想從這個plugin里向外公開一些方法的話,就可以通過向IDesignerCoreService寫入相應(yīng)的方法,在DesignerCoreService里寫入相應(yīng)的實現(xiàn)就可以了。

        三、從注冊表里取出擴展點的類。

        在org.dengues.core里我們寫了一個GlobalServiceFactory里面提供了相應(yīng)的代碼:

            

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的實例了。