文章中如果有图看不到,可以点这里去 csdn 看看。从那边导过来的,文章太多,没法一篇篇修改好。

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 最主要、最典型的设计模式。它是指由外部容器在运行时动态地将组件所依赖的对象(或值)注入进去。
  • 实现方式
    1. 构造器注入 (Constructor Injection)Spring 官方推荐的方式。通过构造器强制注入依赖,能保证依赖不可变且完全初始化。
      @Service
      public class OrderService {
          private final OrderRepository orderRepository;
          // 容器通过此构造器注入
          public OrderService(OrderRepository orderRepository) {
              this.orderRepository = orderRepository;
          }
      }
      
    2. Setter 注入 (Setter Injection):通过 Setter 方法注入,依赖是可变的。
      public class OrderService {
          private OrderRepository orderRepository;
          // 容器通过此Setter方法注入
          public void setOrderRepository(OrderRepository repository) {
              this.orderRepository = repository;
          }
      }
      
    3. 字段注入 (Field Injection):通过反射直接注入字段。不推荐,因为它破坏了封装性,使类难以测试(必须通过容器),且隐藏了设计缺陷(过多的依赖)。
      public class OrderService {
          @Autowired // 不推荐
          private OrderRepository orderRepository;
      }
      

二、Spring IoC 容器核心架构:深入 BeanFactoryApplicationContext

Spring IoC 容器是一个高度模块化和可扩展的体系。其核心层次结构如下:

BeanFactory
+getBean(name)
+getBean(name, requiredType)
+containsBean(name)
+isSingleton(name)
+getType(name)
+getAliases(name)
HierarchicalBeanFactory
+getParentBeanFactory()
ListableBeanFactory
+getBeanDefinitionNames()
+getBeansOfType(type)
+getBeanNamesForAnnotation(annotationType)
AutowireCapableBeanFactory
+createBean(beanClass)
+autowire(requiredType, autowireMode, boolean)
+configureBean(existingBean, name)
+applyBeanPostProcessorsBeforeInitialization(existingBean, name)
ConfigurableBeanFactory
+addBeanPostProcessor(processor)
+registerScope(scopeName, scope)
+getMergedBeanDefinition(beanName)
ConfigurableListableBeanFactory
+preInstantiateSingletons()
+getBeanDefinition(beanName)
+ignoreDependencyType(Class)
«interface»
ApplicationContext
+getId()
+getApplicationName()
+getStartupDate()
+getParent()
+getAutowireCapableBeanFactory()
ConfigurableApplicationContext
+refresh()
+close()
+getBeanFactory()
DefaultListableBeanFactory
-Map<String, BeanDefinition> beanDefinitionMap
-Map<String, Object> singletonObjects
-List<BeanPostProcessor> beanPostProcessors
+registerBeanDefinition(beanName, bd)
+preInstantiateSingletons()
+doCreateBean(beanName, mbd, args)
+populateBean(beanName, mbd, bw)
+initializeBean(beanName, bean, mbd)
AnnotationConfigApplicationContext
-AnnotatedBeanDefinitionReader reader
-ClassPathBeanDefinitionScanner scanner
+AnnotationConfigApplicationContext(componentClasses)
+AnnotationConfigApplicationContext(basePackages)
+refresh()

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 功能之外,集成了大量企业级服务,是“高级”容器。
  • 核心特性
    1. 消息资源管理 (MessageSource):支持国际化 (i18n)。
    2. 应用事件发布 (ApplicationEventPublisher):支持基于观察者模式的事件机制,实现组件间的松耦合通信。
    3. 资源访问 (ResourceLoader):提供统一的 API 来访问底层资源(如文件、URL、类路径资源)。
    4. 层级上下文:支持多个 ApplicationContext 形成父子关系,共享 Bean 定义和某些配置。
    5. 环境抽象 (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

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 生效的关键。

五、高级特性与最佳实践

  1. 循环依赖:Spring 通过三级缓存 (singletonFactories, earlySingletonObjects, singletonObjects) 巧妙地解决了Setter/Field 注入的循环依赖。构造器注入的循环依赖无法解决,因为它发生在实例化阶段,此时无法提前暴露引用。
  2. 作用域 (Scope):除了 singletonprototype,Spring 还提供了 request, session, application 等 Web 作用域。可以通过实现 Scope 接口来自定义作用域。
  3. 延迟初始化 (lazy-init): 对于非延迟加载的单例 Bean,容器启动时就会创建。设置 lazy-init="true" 或使用 @Lazy 注解可以延迟到第一次请求时再创建。
  4. 方法注入 (lookup-method): 用于解决单例 Bean 依赖原型 Bean 的问题,通过动态子类化(CGLIB)重写方法,每次返回一个新的原型实例。
  5. BeanPostProcessor:这是 Spring 框架扩展性的基石。开发者可以实现此接口,在 Bean 初始化前后插入自定义逻辑,如处理自定义注解、代理对象等。
  6. BeanFactoryPostProcessor:允许在容器加载了 BeanDefinition 之后、实例化任何 Bean 之前,修改这些 BeanDefinition 的属性。PropertySourcesPlaceholderConfigurer(处理 ${...})就是其典型应用。

最佳实践总结

  • 使用构造器注入来强制依赖,保证不可变性和完全初始化。
  • 面向接口编程,降低耦合。
  • 保持 Bean 的无状态性,避免线程安全问题。
  • 理解不同作用域的生命周期,避免误用。
  • 谨慎使用字段注入
  • 利用 @Configuration@Bean 进行显式、复杂的配置

Spring IoC 容器是一个极其复杂而又设计精妙的系统。它通过控制反转和依赖注入的原则,将对象创建、依赖管理、生命周期管理等横切关注点集中处理,让开发者能够专注于业务逻辑开发,极大地提升了应用程序的模块化、可测试性和可维护性。

posted @ 2025-09-10 15:48  NeoLshu  阅读(3)  评论(0)    收藏  举报  来源