有人知道Spring在运行时实现依赖注入的技术是什么吗?它只是使用了切面(AOP),还是有更复杂的东西?
有人知道Spring在运行时实现依赖注入的技术是什么吗?它只是使用了切面(AOP),还是有更复杂的东西?
Spring做了很多事情,但依赖注入本身实际上是一个令人惊讶地简单的机制。
它始于有一个注册表来存储可用于注入的类。添加到此注册表中的类会使用反射进行检查。 DI框架将寻找相关的注释和构造函数以确定如何构建这些类的实例,以及这些类可能需要哪些其他依赖项。
注册表还跟踪已创建的实例,以便可以重复使用它们。 重复使用实例涉及作用域,它确定何时可以重复使用实例。 对于单例(Spring的默认设置),实例可以在没有限制的情况下重复使用。
要创建带有依赖项的类的实例,反射被用来创建实例。 如果需要任何依赖关系,则首先创建这些依赖项(如果尚未创建)可能会触发大量递归创建实例。 如果无法创建任何依赖项或存在多个可能的候选项,则框架可以抛出异常以指示配置中的问题。
一个简单的例子,假设我们有一个名为Injector
的类,它既充当类的注册表,又用作创建新实例的工具。
我们注册了一些类:
injector.register(Database.class);
injector.register(EmployeeDao.class);
假设Database类没有进一步的依赖关系,而EmployeeDao依赖于Database:
class EmployeeDao {
@Inject Database db;
}
injector
通过反射机制知道EmployeeDao
依赖于Database
。当我们向injector
请求一个EmployeeDao
的实例时,会发生以下情况:
EmployeeDao employeeDao = injector.getInstance(EmployeeDao.class);
1) 如果已经存在EmployeeDao
实例,则进行检查并返回该实例。
2) 如果不存在,则检查构建EmployeeDao
所需的内容,在这种情况下需要一个Database
。 注入器
使用递归调用自身:
Database database = injector.getInstance(Database.class);
2a) 再次检查是否已经存在一个Database
实例。
2b) 构造Database
不需要进一步的依赖,因此injector
调用Database.class.newInstance()
并跟踪它。
2c) 返回Database
实例。
3) 有了Database
实例可用,injector
现在可以构造EmployeeDao
:EmployeeDao.class.newInstance()
——借助反射,将database
字段注入Database
实例。
4) 注入完成的EmployeeDao
实例被返回。
这是获取类实例的相当直接的方法,然而这正是像Spring这样的DI框架的核心所在。更高级的功能需要创建动态代理和使用AOP,但DI本身归结为使用反射自动构造实例。