构造器注入(Constructor Injection)是 Spring 依赖注入(DI)的一种核心实现方式。在底层,Spring 容器通过 Java 反射机制 和 工厂模式 来接管对象的创建和依赖关系的组装。
具体来说,构造器注入在底层主要执行了以下核心流程:
1. 实例化前的依赖解析(读取图纸)
当 Spring 容器启动并扫描到需要创建的 Bean 时,底层会首先通过反射获取该 Bean 的构造函数信息(包括参数的类型和数量)。Spring 会根据这些参数,从容器中查找匹配的依赖对象(即 BeanDefinition)。如果存在多个候选 Bean,还会通过 @Qualifier 或 @Primary 等注解来明确指定。
2. 递归创建依赖对象
如果在容器中发现所需的依赖 Bean 尚未被创建,Spring 会优先去创建这些依赖 Bean。这个过程可能会形成递归,直到所有的依赖项都被准备好。
3. 调用构造函数完成实例化
当所有依赖对象都准备就绪后,Spring 会使用反射机制调用目标 Bean 的构造函数,并将准备好的依赖对象作为参数传入。这一步是构造器注入的关键,它保证了对象在创建出来的那一刻,就已经是一个包含所有必需依赖的“完整状态”对象。
底层源码级实现分析
在 Spring 的底层源码(如 AbstractAutowireCapableBeanFactory)中,构造器注入的核心逻辑大致如下:
解析构造函数:底层会调用类似
determineConstructor的方法,遍历类中声明的构造函数,查找带有@Autowired注解的构造函数,并验证其参数依赖是否在容器中可用。解析并注入参数:通过
resolvePreparedArguments方法解析构造函数所需的参数对象。反射实例化:最终调用
constructorToUse.newInstance(argsToUse)方法,利用 Java 反射动态创建对象实例,同时将依赖注入其中。
构造器注入的底层优势
由于底层在对象实例化阶段就强制完成了依赖的注入,这种机制带来了几个显著的好处:
避免“半成品”对象:对象创建即处于完整状态,避免了依赖未注入就被使用导致的空指针异常(NPE)。
支持不可变性:因为依赖在构造时就已经确定,类的依赖字段可以被声明为
final,从而保证了线程安全。天然规避循环依赖:由于对象必须在构造时拿到所有依赖,如果 A 依赖 B,B 又依赖 A,Spring 在底层解析构造函数时会直接抛出异常,从而避免了死循环。