Java 框架 Spring Ioc 控制反转 详细分析介绍
一、IoC 与 DI:设计哲学与核心概念
1.1 控制反转 (Inversion of Control)
- 传统控制流:应用程序是主导者,它主动创建和管理所有依赖对象(通过
new关键字)。程序控制着对象的整个生命周期。// 传统代码:紧耦合,控制权在类内部 public class OrderService { // 主动创建依赖,绑定具体实现 private OrderRepository orderRepository = new JdbcOrderRepository(); } - 控制反转:将创建和管理对象的控制权从应用程序代码“反转”给一个外部容器(框架)。应用程序变为被动接收者。
- “好莱坞原则”:Don’t call us, we’ll call you.(不要找我们,我们会找你)。
- 带来的好处:
- 关注点分离:业务代码只需关注业务逻辑,无需关心复杂的依赖创建和管理。
- 解耦:组件之间依赖于抽象(接口),而非具体实现,极大降低了耦合度。
- 可测试性:依赖可以轻松被 Mock 或 Stub 替换,便于单元测试。
- 灵活性:通过更改配置即可改变程序行为,无需修改代码。
1.2 依赖注入 (Dependency Injection)
- 定义:DI 是实现 IoC 最主要、最典型的设计模式。它是指由外部容器在运行时动态地将组件所依赖的对象(或值)注入进去。
- 实现方式:
- 构造器注入 (Constructor Injection):Spring 官方推荐的方式。通过构造器强制注入依赖,能保证依赖不可变且完全初始化。
@Service public class OrderService { private final OrderRepository orderRepository; // 容器通过此构造器注入 public OrderService(OrderRepository orderRepository) { this.orderRepository = orderRepository; } } - Setter 注入 (Setter Injection):通过 Setter 方法注入,依赖是可变的。
public class OrderService { private OrderRepository orderRepository; // 容器通过此Setter方法注入 public void setOrderRepository(OrderRepository repository) { this.orderRepository = repository; } } - 字段注入 (Field Injection):通过反射直接注入字段。不推荐,因为它破坏了封装性,使类难以测试(必须通过容器),且隐藏了设计缺陷(过多的依赖)。
public class OrderService { @Autowired // 不推荐 private OrderRepository orderRepository; }
- 构造器注入 (Constructor Injection):Spring 官方推荐的方式。通过构造器强制注入依赖,能保证依赖不可变且完全初始化。
二、Spring IoC 容器核心架构:深入 BeanFactory 与 ApplicationContext
Spring IoC 容器是一个高度模块化和可扩展的体系。其核心层次结构如下:
2.1 BeanFactory - 基础容器
- 定位:IoC 的核心基础设施接口,提供了最基本的 DI 功能。它是一个“低级”容器。
- 设计模式:使用了 “模板方法模式 (Template Method Pattern)”。
DefaultListableBeanFactory实现了核心算法骨架,而许多步骤(如createBean)可以被重写以提供自定义行为。 - 核心方法:
getBean(),isSingleton(),getType(),getAliases()。 - 重要子接口:
HierarchicalBeanFactory:提供容器继承(父子层级)的能力。子容器可以访问父容器中的 Bean。ListableBeanFactory:提供了枚举所有 Bean 定义的能力,如getBeanDefinitionNames(),getBeansOfType()。AutowireCapableBeanFactory:提供了自动装配和 Bean 生命周期管理(创建、填充、初始化、销毁)的核心能力。ConfigurableBeanFactory:提供了配置容器行为的方法,如添加BeanPostProcessor、注册自定义Scope。
- 核心实现:
DefaultListableBeanFactory是一个功能完整、独立、可编程使用的 IoC 容器实现。它是整个 Spring IoC 的发动机。ApplicationContext的所有实现最终都委托它来完成 Bean 的创建和管理。
2.2 ApplicationContext - 高级容器
- 定位:是
BeanFactory的超集,在提供所有基础 DI 功能之外,集成了大量企业级服务,是“高级”容器。 - 核心特性:
- 消息资源管理 (MessageSource):支持国际化 (i18n)。
- 应用事件发布 (ApplicationEventPublisher):支持基于观察者模式的事件机制,实现组件间的松耦合通信。
- 资源访问 (ResourceLoader):提供统一的 API 来访问底层资源(如文件、URL、类路径资源)。
- 层级上下文:支持多个
ApplicationContext形成父子关系,共享 Bean 定义和某些配置。 - 环境抽象 (Environment):统一访问环境变量、JVM 系统属性、配置文件(如
application.properties)等。
- 重要实现:
AnnotationConfigApplicationContext:基于 Java 注解(如@Configuration,@Bean)配置的独立应用容器。ClassPathXmlApplicationContext:基于 XML 配置的传统独立应用容器。AnnotationConfigWebApplicationContext/XmlWebApplicationContext:用于 Web 环境的容器(Spring MVC)。
三、配置元数据 (BeanDefinition) 的加载与解析
容器需要知道如何创建和组装对象。这些信息称为配置元数据 (Configuration Metadata),它在容器内部被抽象为 BeanDefinition 对象。
3.1 BeanDefinition - 配置的内部抽象
一个 BeanDefinition 对象包含了创建一个 Bean 所需的全部信息:
- 类名:Bean 的全限定类名。
- Bean 行为配置:作用域(单例/原型)、是否懒加载、初始化方法、销毁方法。
- 依赖关系:构造器参数、属性值,以及对其他 Bean 的引用。
- 其他配置:是否为主候选 Bean(
@Primary)、装饰器模式(Decorator)等。
3.2 元数据的加载与注册过程
不同的 ApplicationContext 实现使用不同的 BeanDefinitionReader 来读取配置并注册 BeanDefinition。
AnnotatedBeanDefinitionReader:- 处理
@Configuration,@Bean,@Component等注解。 - 内部使用
ConfigurationClassPostProcessor(一个BeanDefinitionRegistryPostProcessor)来解析配置类。它会递归解析@Import,@ComponentScan等注解,最终将扫描到的所有@Component类和@Bean方法注册为BeanDefinition。
- 处理
ClassPathBeanDefinitionScanner:- 直接扫描指定的包路径,查找带有
@Component及其派生注解的类,并将其注册为BeanDefinition。
- 直接扫描指定的包路径,查找带有
XmlBeanDefinitionReader:- 解析 XML 文件中的
<bean>标签,将其转换为BeanDefinition。
- 解析 XML 文件中的
BeanDefinitionRegistry:这是 DefaultListableBeanFactory 实现的另一个核心接口,它像一个 Map,负责注册和保存 BeanDefinition。
四、Bean 生命周期的超详细过程
这是 Spring IoC 最核心的部分。我们再次深入 DefaultListableBeanFactory.doCreateBean()。
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
// 1. Instantiation
BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);
Object bean = instanceWrapper.getWrappedInstance();
// 2. MergedBeanDefinitionPostProcessor (MBD-PP)
// e.g., AutowiredAnnotationBeanPostProcessor scans @Autowired, @Value, @Inject
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
// 3. Early exposure for circular references
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
// Add SingletonFactory to level 3 cache
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// 4. Population (DI)
Object exposedObject = bean;
populateBean(beanName, mbd, instanceWrapper); // ★ Inject dependencies here!
// 5. Initialization
exposedObject = initializeBean(beanName, exposedObject, mbd);
// ... (circular reference handling and registration)
return exposedObject;
}
4.1 populateBean() - 依赖注入的圣地
此方法负责属性填充和依赖注入。
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// ... (checks)
// 1. InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()
// Can short-circuit population if returns false.
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return; // Stop population
}
}
}
}
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 2. Autowire by name/type (from XML)
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
// 3. ★★★ InstantiationAwareBeanPostProcessor.postProcessProperties() ★★★
// This is where @Autowired, @Value, @Inject are processed!
if (hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// The processor does the actual dependency resolution and injection
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
// ... (fallback handling)
}
}
}
}
// 4. Apply property values from XML (if any)
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
- 关键处理器:
AutowiredAnnotationBeanPostProcessor在其postProcessProperties()方法中,会查找之前缓存的注入元数据(InjectionMetadata),然后为每个需要注入的字段/方法调用beanFactory.resolveDependency()。这个方法最终会调用getBean()来获取依赖的 Bean,这可能触发另一个 Bean 的创建流程,是递归和循环依赖的根源。
4.2 initializeBean() - 初始化的殿堂
此方法负责处理所有初始化回调。
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
// 1. Invoke Aware interfaces
invokeAwareMethods(beanName, bean); // BeanNameAware, BeanClassLoaderAware, BeanFactoryAware
Object wrappedBean = bean;
// 2. Apply BeanPostProcessors BEFORE initialization
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
// 3. Invoke init methods
try {
invokeInitMethods(beanName, wrappedBean, mbd); // InitializingBean.afterPropertiesSet(), custom init-method
} catch (Throwable ex) {
// ... handle exception
}
// 4. Apply BeanPostProcessors AFTER initialization
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
applyBeanPostProcessorsBeforeInitialization():ApplicationContextAwareProcessor:处理各种ApplicationContext相关的Aware接口(EnvironmentAware,ResourceLoaderAware等)。InitDestroyAnnotationBeanPostProcessor(在CommonAnnotationBeanPostProcessor中):执行@PostConstruct注解的方法。
applyBeanPostProcessorsAfterInitialization():AnnotationAwareAspectJAutoProxyCreator:检查当前 Bean 是否匹配任何切面。如果匹配,则创建一个代理对象并返回,否则返回原始对象。 这是 AOP 生效的关键。
五、高级特性与最佳实践
- 循环依赖:Spring 通过三级缓存 (
singletonFactories,earlySingletonObjects,singletonObjects) 巧妙地解决了Setter/Field 注入的循环依赖。构造器注入的循环依赖无法解决,因为它发生在实例化阶段,此时无法提前暴露引用。 - 作用域 (Scope):除了
singleton和prototype,Spring 还提供了request,session,application等 Web 作用域。可以通过实现Scope接口来自定义作用域。 - 延迟初始化 (
lazy-init): 对于非延迟加载的单例 Bean,容器启动时就会创建。设置lazy-init="true"或使用@Lazy注解可以延迟到第一次请求时再创建。 - 方法注入 (
lookup-method): 用于解决单例 Bean 依赖原型 Bean 的问题,通过动态子类化(CGLIB)重写方法,每次返回一个新的原型实例。 BeanPostProcessor:这是 Spring 框架扩展性的基石。开发者可以实现此接口,在 Bean 初始化前后插入自定义逻辑,如处理自定义注解、代理对象等。BeanFactoryPostProcessor:允许在容器加载了BeanDefinition之后、实例化任何 Bean 之前,修改这些BeanDefinition的属性。PropertySourcesPlaceholderConfigurer(处理${...})就是其典型应用。
最佳实践总结:
- 使用构造器注入来强制依赖,保证不可变性和完全初始化。
- 面向接口编程,降低耦合。
- 保持 Bean 的无状态性,避免线程安全问题。
- 理解不同作用域的生命周期,避免误用。
- 谨慎使用字段注入。
- 利用
@Configuration和@Bean进行显式、复杂的配置。
Spring IoC 容器是一个极其复杂而又设计精妙的系统。它通过控制反转和依赖注入的原则,将对象创建、依赖管理、生命周期管理等横切关注点集中处理,让开发者能够专注于业务逻辑开发,极大地提升了应用程序的模块化、可测试性和可维护性。
本文来自博客园,作者:NeoLshu,转载请注明原文链接:https://www.cnblogs.com/neolshu/p/19120644

浙公网安备 33010602011771号