Java自動依賴注入框架:Pure.IoC

jopen 9年前發布 | 59K 次閱讀 Pure.IoC 面向方面AOP/IoC

Pure.IoC

Pure.IoC是一個輕量級基于類和注解的自動依賴注入框架。

使用jdk 1.8
此框架依賴于Style函數式工具集v1.1.1
如果需要debug輸出,則還依賴于log4j 1.2.17
推薦與Spring配合使用

框架思想

已有的邏輯關系代替復雜的配置

設計思路

通常寫java時會使用Spring框架進行IoC管理。而Spring是基于bean的,配置起來首先需要將類映射到bean,然后描述bean的依賴關系。

事實上,很多時候依賴關系僅僅需要類型即可確定。比如說

class A{
    ...
    public void setB(B b){ this.b=b; }
}

class B{
}

很顯然,A依賴于B,A需要將一個B的實例通過setB注入進來。這應當是很自然的邏輯關系。

類型依賴在編碼時就會設定好,所以,如果有工具能幫助完成這類“顯而易見”的依賴該多好。于是我開發了Pure.IoC

框架的框架

擴展性

設計Pure.IoC時經歷了不少思考。考慮下面這樣的“復雜”情況(其實已經算不復雜了)

@Singleton
@Wire
class Complex{
    private ......

    public Complex(){ ... }
    @Default public Complex(AnotherClass obj){ ... }

    public void setA(A a){ ... }
    public void setB(B b){ ... }    
    public void setInterface(Interf1 interf){ ... }
    public void setInterface(@Use(clazz=Impl2.class)Interf2 interf){ ... }
}

@Default(clazz=Impl1.class) interface Interf1{ ... }

上述注解描述了:

  • @Singleton Complex是一個單例
  • @Wire 在通過AutoWire構建時需要注入
  • @Default 指定默認的構造器(構造函數上),指定默認的實現類(接口上)
  • @Use 指定使用的類

注解應當可以無限的附加,也不能增加系統復雜性。
所以,最終使用這種設計:

AnnotationHandler + HandlerChain

AnnotationHandler分為四種,

  • SetterAnnotationHandler 負責調用Setter,考慮setter,對應成員,和setter參數上的注解
  • ParamAnnotationHandler 負責根據類型獲取實例,考慮參數上的注解
  • ConstructorFilter 負責選擇構造器,考慮構造器上的注解
  • TypeAnnotationHandler 負責選取要構造的類型,考慮類型上的注解

Handler被注冊到IOCController上,根據注冊的順序進行handling操作。handler的內部實現有點像AOP,一般來說會調用chain.next().handle(...) ,然后根據返回值或者異常進行一些邏輯判斷。詳情見各Handler接口的handle方法文檔

所以,可以非常方便的進行注解的擴展。

循環依賴

循環依賴雖然不很常見,但沒準會遇到。A->B->C->A
從邏輯上,A,B,C中必須有一個是單例,否則對象的創建將無限循環下去。

另外: Spring要求構造器不能循環依賴,否則無法完成構建。

不過Pure.IoC巧妙的解決了循環依賴的問題。

  • 所有注入在構造時進行。只有注入完成,構造才會完成。
  • 對于單例,在構造實際進行前把自己的引用交給IOCController,指示單例已經存在
  • 由于只有注入完成才構造完成,所以不必擔心獲取到一個構造一半的對象。

所以,即使是構造器中包含循環依賴,也能順利的進行(本質上所有依賴都是構造器依賴)。

適用性

Pure.IoC由于設計為構造時注入,所以不需要任何額外組建即可放入框架中使用。也可配合Spring使用。甚至可以一部分setter通過本框架注入,一部分通過Spring注入。

直接與Struts2等相接也可以。由于注入過程完全在類內部,所以并不需要像Spring一樣配置接管Struts2的對象工廠,而是直接就可使用(一個對象本身就是注入“工廠”)。

推薦的使用方法是

extends AutoWire

但是有些情況下必須繼承別的類,那么有兩種解決辦法:

1.

@Wire class A { ... }

@Wire注解標注的類在任何經過Pure.IoC的情況下都會進行注入操作。
在單獨獲取時可使用

AutoWire.get(A.class)

獲取實例

2.

class A {
    public A(){
        AutoWire.wire(this);
    }
}

構造時將自己的引用交給框架進行注入。

實際上所有入口最終都調用AutoWire.wire(Object)

如何使用?

首先使用上述三種方法任何一種進行框架接入。

默認行為

沒有任何注解參與時的默認行為是:

注入setter時,獲取參數類型并向IOCController請求實例,獲取實例后進行setter的invoke。

在獲取實例時,取得唯一一個構造器,或者取得無參數的構造器。
如果構造器有參數,則取得參數類型對應實例。
最后進行構造

擴展注解

Setter

  • Use(clazz, constant, variable)
    clazz代表使用指定的類型作注入 接下來會對指定的類型進行Type檢查。
    constant代表之前在IOCController上注冊的“常量”
    variable代表之前在IOCController上注冊的“變量”,必須是一些static的成員或者方法。

  • Force(value)
    將String類型的value轉化為對應的類型。Force只支持基本類型和String

  • Ignore
    忽略該setter

Type

  • Wire 指示該類需要注入
  • IsSingleton
    指示該類為單例
  • Default(clazz)
    一般用于interface或者abstract class
    在Type檢查時若遇到該注解則會轉而構造該注解指定的類型

Constructor

  • Default()
    在可能產生歧義時指定構造時默認使用的構造函數

Param

  • Use(clazz, constant, variable)
    clazz代表使用指定的類型作注入 接下來會對指定的類型進行Type檢查。
    constant代表之前在IOCController上注冊的“常量”
    variable代表之前在IOCController上注冊的“變量”,必須是一些static的成員或者方法。
  • Force(value)
    將String類型的value轉化為對應的類型。Force只支持基本類型和String

此外,進行Param處理時還提供自動的基本類型注入。
若沒有找到可用的注入,則將檢查基本類型和數組類型,并初始化為默認初始值(0,false,array[length=0])

項目主頁:http://www.baiduhome.net/lib/view/home/1441010472393

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!