在Eclipse RCP中實現反轉控制(IoC)

Eclipse富客戶平臺(RCP)是一個功能強大的軟件平臺,它基於插件間的互連與協做,容許開發人員構建通用的應用程序。RCP使開發人員能夠集中精力進行應用程序業務代碼的開發,而不須要花費時間從新發明輪子編寫應用程序管理的邏輯。

  反轉控制(Inversion of Control, IoC)和依賴注入(Dependency Injection, DI)是兩種編程模式,可用於減小程序間的耦合。它們遵循一個簡單的原則:你不要建立你的對象;你描述它們應當如何被建立。你不要實例化你的部件所須要對象或直接定位你的部件所須要的服務;相反,你描述哪一個部件須要哪些服務,其它人(一般是一個容器)負責將它們鏈接到一塊兒。這也被認爲是好萊塢法則:don't call us--we'll call you。

  本文將描述一個簡單的方式在Eclipse RCP應用程序中使用依賴注入。爲了不污染Eclipse 平臺的基礎結構以及透明地在RCP之上添加IoC框架,咱們將結合使用運行時字節碼操做技術(使用 ObjectWeb ASM庫)、Java類加載代理(使用java.lang.instrument包)以及Java annotation。

   什麼是Eclipse富客戶平臺?

  用一句話來說,富客戶平臺是一個類庫、軟件框架的集合,它是一個用於構建單機和連網應用程序的運行時環境。

  儘管Eclipse被認爲是構建集成開發環境(IDE)的框架,從3.0開始,Eclipse整個產品進行了重構,分割成各類不一樣的部件,它些部件能夠用於構建任意的應用程序。其中的一個子集構成了富客戶平臺,它包含如下元素:基本的運行時環境、用戶界面組件(SWT和JFace)、插件以及 OSGI層。圖1顯示了Eclipse平臺的主要部件。

Eclipse平臺的主要部件
圖1. Eclipse平臺的主要部件

  整個Eclipse平臺是基於插件和擴展點。一個 插件是一個能夠獨立開發和發佈的最小的功能單元。它一般打包成一個 jar文件,經過添加功能(例如,一個編輯器、一個工具欄按鈕、或一個編譯器)來擴展平臺。整個平臺是一個相互鏈接和通訊的插件的集合。一個 擴展點是一個互相鏈接的端點,其它插件能夠用它提供額外的功能(在Eclipse中稱爲 擴展)。擴展和擴展點定義在XML配置文件中,XML文件與插件捆綁在一塊兒。

  插件模式增強了關注分離的概念,插件間的強鏈接和通信須要經過配線進行設置它們之間的依賴。典型的例子源自須要定位應用程序所須要的單子服務,例如數據庫鏈接池、日誌處理或用戶保存的首選項。反轉控制和依賴注入是消除這種依賴的可行解決方案。

   反轉控制和依賴注入

  反轉控制是一種編程模式,它關注服務(或應用程序部件)是如何定義的以及他們應該如何定位他們依賴的其它服務。一般,經過一個容器或定位框架來得到定義和定位的分離,容器或定位框架負責:
  • 保存可用服務的集合
  • 提供一種方式將各類部件與它們依賴的服務綁定在一塊兒
  • 爲應用程序代碼提供一種方式來請求已配置的對象(例如,一個全部依賴都知足的對象), 這種方式能夠確保該對象須要的全部相關的服務均可用。
  現有的框架實際上使用如下三種基本技術的框架執行服務和部件間的綁定:
  • 類型1 (基於接口): 可服務的對象須要實現一個專門的接口,該接口提供了一個對象,能夠從用這個對象查找依賴(其它服務)。早期的容器Excalibur使用這種模式。
  • 類型2 (基於setter): 經過JavaBean的屬性(setter方法)爲可服務對象指定服務。HiveMind和Spring採用這種方式。
  • 類型3 (基於構造函數): 經過構造函數的參數爲可服務對象指定服務。PicoContainer只使用這種方式。HiveMind和Spring也使用這種方式。
  咱們將採用第二種方式的一個變種,經過標記方式來提供服務(下面示例程序的源代碼能夠在資源部分獲得)。 聲明一個依賴能夠表示爲:
@Injected public void aServicingMethod(Service s1, AnotherService s2) { 
  // 將s1和s2保存到類變量,須要時可使用 
}
  反轉控制容器將查找Injected註釋,使用請求的參數調用該方法。咱們想將IoC引入Eclipse平臺,服務和可服務對象將打包放入Eclipse插件中。插件定義一個擴展點 (名稱爲com.onjava.servicelocator.servicefactory),它能夠向程序提供服務工廠。當可服務對象須要配置時,插件向一個工廠請求一個服務實例。ServiceLocator類將完成全部的工做,下面的代碼描述該類(咱們省略了分析擴展點的部分,由於它比較直觀):
public static void service(Object serviceable) throws ServiceException { 
        ServiceLocator sl = getInstance(); 
        if (sl.isAlreadyServiced(serviceable)) { 
            // prevent multiple initializations due to 
            // constructor hierarchies 
            System.out.println("Object " + serviceable 
                    + " has already been configured "); 
            return; 
        } 

        System.out.println("Configuring " + serviceable); 

        // Parse the class for the requested services 
        for (Method m : serviceable.getClass().getMethods()) { 
            boolean skip = false; 
            Injected ann = m.getAnnotation(Injected.class); 
            if (ann != null) { 
                Object[] services = new Object[m.getParameterTypes().length]; 
                int i = 0; 

                for (Class<?> class : m.getParameterTypes()) { 
                    IServiceFactory factory = sl.getFactory(class, ann 
                            .optional()); 
                    if (factory == null) { 
                        skip = true; 
                        break; 
                    } 
                    Object service = factory.getServiceInstance(); 

                    // sanity check: verify that the returned 
                    // service's class is the expected one 
                    // from the method 
                    assert (service.getClass().equals(class) || class 
                            .isAssignableFrom(service.getClass())); 

                    services[i++] = service; 
                } 

                try { 
                    if (!skip) 
                        m.invoke(serviceable, services); 
                } catch (IllegalAccessException iae) { 
                    if (!ann.optional()) 
                        throw new ServiceException( 
                                "Unable to initialize services on " 
                                        + serviceable + ": " + iae.getMessage(), iae); 
                } catch (InvocationTargetException ite) { 
                    if (!ann.optional()) 
                        throw new ServiceException( 
                                "Unable to initialize services on " 
                                        + serviceable + ": " + ite.getMessage(), ite); 
                } 
            } 
        } 

        sl.setAsServiced(serviceable); 
    }

  因爲服務工廠返回的服務可能也是可服務對象,這種策略容許定義服務的層次結構(然而目前不支持循環依賴)。

「七」樂無窮,盡在新浪新版博客,快來體驗啊~~~請點擊進入~html

相關文章
相關標籤/搜索