Spring Bean 生命周期

Spring Bean 生命周期


一、Bean 的创建方式与底层实现

Spring 中 Bean 的创建方式及其底层源码实现是理解生命周期的关键。以下是常见的 Bean 注册方式及其源码层面的核心逻辑:


1. XML 配置方式
<bean id="userService" class="com.example.UserService" init-method="init" destroy-method="cleanup"/>

源码分析

  • 解析阶段XmlBeanDefinitionReader 解析 XML 文件,生成 BeanDefinition 并注册到 BeanFactorybeanDefinitionMap
  • 注册逻辑DefaultListableBeanFactory.registerBeanDefinition()BeanDefinition 存入 ConcurrentHashMap
  • 注意事项
    • 显式声明依赖()以避免隐式注入的歧义。
    • 避免 init-methoddestroy-method 命名冲突。

2. 注解方式(@Component、@Service 等)
@Component
public class UserService { ... }

源码分析

  • 扫描阶段ClassPathBeanDefinitionScanner 扫描 @Component 注解的类,生成 ScannedGenericBeanDefinition
  • 注册逻辑BeanDefinitionReaderUtils.registerBeanDefinition() 将 Bean 定义注册到容器。
  • 注意事项
    • 组件扫描路径:必须配置 @ComponentScan 或在 XML 中启用
    • 性能问题:扫描范围过大会导致启动变慢(可通过 basePackages 精确控制)。

3. Java 配置类(@Configuration + @Bean)
@Configuration
public class AppConfig {
    @Bean(initMethod = "init", destroyMethod = "close")
    public DataSource dataSource() {
        return new HikariDataSource();
    }
}

源码分析

  • 代理机制@Configuration 类会被 CGLIB 代理,确保 @Bean 方法返回单例对象。
  • 注册逻辑ConfigurationClassPostProcessor 处理 @Bean 方法,生成 BeanDefinition
  • 注意事项
    • 单例与原型:默认单例,若需原型需显式指定 @Scope("prototype")
    • 跨 Bean 方法调用:直接调用 @Bean 方法会绕过代理,导致单例失效(应通过参数注入依赖)。

4. 动态注册(BeanDefinitionRegistry)
public class DynamicBeanRegistrar implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        GenericBeanDefinition definition = new GenericBeanDefinition();
        definition.setBeanClass(DynamicService.class);
        registry.registerBeanDefinition("dynamicService", definition);
    }
}

源码分析

  • 扩展点BeanDefinitionRegistryPostProcessor 允许在容器初始化阶段修改 BeanDefinition
  • 使用场景:插件化架构、运行时动态注册 Bean。
  • 注意事项
    • 注册顺序:需在 BeanFactory 冻结前完成注册(refresh()invokeBeanFactoryPostProcessors 阶段)。
    • 依赖管理:动态 Bean 的依赖需手动处理。

二、Bean 生命周期核心流程与源码解析

1. 实例化(Instantiation)
  • 源码入口AbstractAutowireCapableBeanFactory.createBeanInstance()
  • 关键逻辑
    • 优先使用构造器注入(解析 ConstructorResolver)。
    • 若存在 Supplier(如 @Bean 方法),则通过 Objenesis 或反射创建实例。
  • 问题示例
    // 构造器循环依赖导致无法解决
    public class A {
        public A(B b) { ... }
    }
    public class B {
        public B(A a) { ... }
    }
    
    解决方案
    • 使用 @Lazy 延迟注入。
    • 改用 Setter 注入。

2. 属性填充(Population)
  • 源码入口AbstractAutowireCapableBeanFactory.populateBean()
  • 依赖注入方式
    • 字段注入AutowiredAnnotationBeanPostProcessor 处理 @Autowired
    • Setter 注入BeanWrapperImpl.setPropertyValues()
  • 循环依赖解决
    • 三级缓存DefaultSingletonBeanRegistry 维护三级缓存:
      • singletonObjects:完整 Bean。
      • earlySingletonObjects:早期引用(已实例化但未初始化)。
      • singletonFactoriesObjectFactory 用于生成早期代理对象。
    • 流程:当 A 依赖 B 时,A 实例化后放入三级缓存 → 填充 B 时触发 B 的创建 → B 填充 A 时从三级缓存获取 A 的早期引用。

3. 初始化(Initialization)
  • 源码入口AbstractAutowireCapableBeanFactory.initializeBean()
  • 执行顺序
    1. BeanPostProcessor.postProcessBeforeInitialization()(如 @PostConstruct 处理)。
    2. InitializingBean.afterPropertiesSet()
    3. 自定义 init-method
    4. BeanPostProcessor.postProcessAfterInitialization()(如 AOP 代理生成)。
  • AOP 代理生成
    • AbstractAutoProxyCreator.postProcessAfterInitialization() 创建代理对象。
    • 若 Bean 实现了接口,默认使用 JDK 动态代理;否则使用 CGLIB。

4. 销毁(Destruction)
  • 源码入口DisposableBeanAdapter.destroy()
  • 执行顺序
    1. @PreDestroy 方法。
    2. DisposableBean.destroy()
    3. 自定义 destroy-method
  • 触发时机ApplicationContext.close() 或注册 ConfigurableApplicationContext 的 Shutdown Hook。

三、常见问题与源码级解决方案

1. 循环依赖(Circular Dependency)
  • 问题场景:构造器注入导致的循环依赖无法解决。
  • 源码分析
    • Spring 仅支持通过 Setter/字段注入解决循环依赖,构造器注入会在 beforeSingletonCreation() 中抛出 BeanCurrentlyInCreationException
    • 三级缓存源码
      protected Object getSingleton(String beanName, boolean allowEarlyReference) {
          Object singletonObject = this.singletonObjects.get(beanName);
          if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
              singletonObject = this.earlySingletonObjects.get(beanName);
              if (singletonObject == null && allowEarlyReference) {
                  synchronized (this.singletonObjects) {
                      // 从 singletonFactories 获取 ObjectFactory 并生成早期引用
                      ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                      if (singletonFactory != null) {
                          singletonObject = singletonFactory.getObject();
                          this.earlySingletonObjects.put(beanName, singletonObject);
                          this.singletonFactories.remove(beanName);
                      }
                  }
              }
          }
          return singletonObject;
      }
      
  • 解决方案
    • 使用 @Lazy 延迟加载其中一个 Bean。
    • 避免构造器循环依赖,改用 Setter 注入。

2. Bean 覆盖问题
  • 问题场景:多个同名的 BeanDefinition 导致覆盖。
  • 源码分析
    • DefaultListableBeanFactoryallowBeanDefinitionOverriding 属性控制是否允许覆盖(默认 true)。
    • Spring Boot 默认禁用覆盖(spring.main.allow-bean-definition-overriding=false)。
  • 解决方案
    • 显式配置 Bean 名称避免冲突。
    • 在 Spring Boot 中启用覆盖需谨慎。

3. 初始化顺序问题
  • 问题场景:Bean A 依赖 Bean B,但 B 尚未初始化。
  • 源码分析
    • DefaultListableBeanFactorypreInstantiateSingletons() 按注册顺序初始化 Bean。
    • @DependsOn 注解会修改依赖顺序。
  • 解决方案
    • 使用 @DependsOn("b") 显式声明依赖顺序。
    • 通过 SmartInitializingSingleton 接口在单例初始化完成后执行逻辑。

四、代码示例与调试技巧

1. 调试 Bean 生命周期
public class DebugBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        System.out.println("BeforeInit: " + beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        System.out.println("AfterInit: " + beanName);
        return bean;
    }
}
  • 作用:通过自定义 BeanPostProcessor 观察初始化阶段。

2. 动态注册 Bean
public class DynamicBeanRegistrar implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        RootBeanDefinition definition = new RootBeanDefinition(DynamicBean.class);
        definition.setLazyInit(true);
        registry.registerBeanDefinition("dynamicBean", definition);
    }
}
  • 场景:运行时根据条件动态注册 Bean。

你可能感兴趣的:(spring,python,java)