【发布时间】:2017-09-16 19:16:13
【问题描述】:
有谁知道spring使用什么技术在运行时实现依赖注入?它是简单地使用方面(AOP)还是更复杂的东西?
【问题讨论】:
标签: java spring dependency-injection aop
有谁知道spring使用什么技术在运行时实现依赖注入?它是简单地使用方面(AOP)还是更复杂的东西?
【问题讨论】:
标签: java spring dependency-injection 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。 injector 递归调用自身:
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 本身归结为使用反射来自动构造实例。
【讨论】: