依赖注入框架并不神秘,其实它是很是简单的东西。不要去看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的设计与实现