依賴注入介紹
先回顧下依賴注入的概念:
我們常提起的依賴注入(Dependency Injection)和控制反轉(Inversion of Control)是同一個概念。具體含義是:當某個角色(可能是一個Java實例,調用者)需要另一個角色(另一個Java實例,被調用者)的協助時,在傳統的程序設計過程中,通常由調用者來創建被調用者的實例。但在Spring裡,創建被調用者的工作不再由調用者來完成,因此稱為控制反轉;創建被調用者實例的工作通常由Spring容器來完成,然後注入調用者,因此也稱為依賴注入。
其實簡單的說,依賴注入起到的作用就是講對象之間的依賴關係從原先的代碼中解耦出來,通過配置文件或註解等方式加上Spring框架的處理讓我們對依賴關係靈活集中的進行管理。
依賴注入框架
依賴注入框架並不神秘,其實它是非常簡單的東西。不要去看spring的依賴注入源碼,因為你只要一去看就意味著你再也寫不敢下手自己擼了,它的功能因為過於強大,所以設計也過於復雜,普通程序員一眼看去只能望洋興嘆。
我也並沒有去細緻閱讀spring源碼。即便如此也只用了半天的時間便自己擼了一個基本滿足標準依賴注入規範「JSR-330」的小框架iockids。這個小框架只有一個主類Injector,大約200行代碼,它具備以下功能。
我們看一個稍微複雜一點的使用示例
import javax.inject.Inject;import javax.inject.Named;import javax.inject.Singleton;import iockids.Injector;@Singletonclass Root { @Inject @Named("a") Node a; @Inject @Named("b") Node b; @Override public String toString() { return String.format("root(%s, %s)", a.name(), b.name()); }}interface Node { String name();}@Singleton@Named("a")class NodeA implements Node { @Inject Leaf leaf; @Inject @Named("b") Node b; @Override public String name() { if (b == null) return String.format("nodeA(%s)", leaf); else return String.format("nodeAWithB(%s)", leaf); }}@Singleton@Named("b")class NodeB implements Node { Leaf leaf; @Inject @Named("a") Node a; @Inject public NodeB(Leaf leaf) { this.leaf = leaf; } @Override public String name() { if (a == null) return String.format("nodeB(%s)", leaf); else return String.format("nodeBWithA(%s)", leaf); }}class Leaf { @Inject Root root; int index; static int sequence; public Leaf() { index = sequence++; } public String toString() { if (root == null) return "leaf" + index; else return "leafwithroot" + index; }}public class Demo { public static void main(String[] args) { var injector = new Injector(); injector.registerQualifiedClass(Node.class, NodeA.class); injector.registerQualifiedClass(Node.class, NodeB.class); var root = injector.getInstance(Root.class); System.out.println(root); }}上面這份代碼用到了iockids提供的所有功能。
為了便於理解上述代碼,我畫了依賴圖
上面的代碼輸出如下
root(nodeAWithB(leafwithroot0), nodeBWithA(leafwithroot1))
從這個輸出中,我們也可以大致想像出依賴結構。
iockids提供了豐富的注入錯誤異常報告,防止用戶注入配置出錯。
比如我們將上面的NodeA和NodeB的名稱都配置成一樣的a,就會曝出下面的錯誤堆棧
iockids.InjectException: duplicated qualifier javax.inject.Named with the same class iockids.demo.Node at iockids.Injector.registerQualifiedClass(Injector.java:87) at iockids.Injector.registerQualifiedClass(Injector.java:70) at iockids.demo.Demo.main(Demo.java:106)
如果我們將NodeB的構造器隨意加一個參數
@Inject public NodeB(Leaf leaf, int k) { this.leaf = leaf; }運行時就會拋出下面的錯誤
iockids.InjectException: no accessible constructor for injection class int at iockids.Injector.createNew(Injector.java:120) at iockids.Injector.createNew(Injector.java:94) at iockids.Injector.createFromParameter(Injector.java:167) at iockids.Injector.createFromConstructor(Injector.java:145) at iockids.Injector.createNew(Injector.java:123) at iockids.Injector.createFromQualified(Injector.java:216) at iockids.Injector.createFromField(Injector.java:173) at iockids.Injector.injectMembers(Injector.java:233) at iockids.Injector.createNew(Injector.java:136) at iockids.Injector.createFromQualified(Injector.java:216) at iockids.Injector.createFromField(Injector.java:173) at iockids.Injector.injectMembers(Injector.java:233) at iockids.Injector.createNew(Injector.java:136) at iockids.Injector.createNew(Injector.java:94) at iockids.Injector.getInstance(Injector.java:245) at iockids.demo.Demo.main(Demo.java:107)
項目開源地址:https://github.com/pyloque/iockids(本地下載)
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對武林網的支持。