依賴注入框架並不神祕,其實它是很是簡單的東西。不要去看spring的依賴注入源碼,由於你只要一去看就意味着你再也寫不敢下手本身擼了,它的功能由於過於強大,因此設計也過於複雜,普通程序員一眼看去只能望洋興嘆。java
我也並無去細緻閱讀spring源碼。即使如此也只用了半天的時間便本身擼了一個基本知足標準依賴注入規範「JSR-330」的小框架iockids。這個小框架只有一個主類Injector,大約200行代碼,它具有如下功能。node
咱們看一個稍微複雜一點的使用示例git
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import iockids.Injector;
@Singleton
class 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提供的全部功能。程序員
爲了便於理解上述代碼,我畫了依賴圖github
上面的代碼輸出以下spring
root(nodeAWithB(leafwithroot0), nodeBWithA(leafwithroot1))
複製代碼
從這個輸出中,咱們也能夠大體想象出依賴結構。bash
iockids提供了豐富的注入錯誤異常報告,防止用戶注入配置出錯。框架
好比咱們將上面的NodeA和NodeB的名稱都配置成同樣的a,就會曝出下面的錯誤堆棧ide
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的構造器隨意加一個參數this
@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
關注公衆號「碼洞」,和大佬們一塊兒來討論iockids的設計與實現