【大白话说Java面试题 第151题】【06_Spring篇】第11题:说一下 Spring Bean 的生命周期?

📌 PDF :大白话说Java面试题 --- 06_Spring篇

第11题:说一下 Spring Bean 的生命周期

📚 回答:

  • 核心考点 : Spring Bean 的生命周期是 Spring 框架最核心的机制之一,大厂面试不会只问"有哪几个阶段",而是深入考察 BeanDefinition 的合并与后置处理MergedBeanDefinitionPostProcessor)、三级缓存解决循环依赖的源码级原理singletonObjects/earlySingletonObjects/singletonFactories)、推断构造方法的完整算法autowireConstructor)、初始化阶段的三层回调顺序@PostConstructInitializingBean → 自定义 init)、AOP 代理的创建时机与 BeanPostProcessor 的作用以及 SmartInitializingSingletonDestructionAwareBeanPostProcessor 等扩展点。面试官真正想判断的是:你是否能从源码层面理解 Spring 容器的完整创建链路,以及能否在循环依赖、AOP 代理、初始化顺序等生产级场景中定位和解决问题。

1. 生命周期的完整阶段------从源码视角梳理

Spring Bean 的生命周期是一个精密的流水线,涉及 IoC 容器、依赖注入、AOP 代理、事件机制等多个子系统的协同。以下是完整的生命周期阶段:

复制代码
【阶段1】加载 BeanDefinition
    ↓
【阶段2】BeanDefinition 合并与后置处理
    ↓
【阶段3】推断构造方法并实例化
    ↓
【阶段4】依赖注入(属性填充)
    ↓
【阶段5】初始化前处理(Aware 接口、@PostConstruct)
    ↓
【阶段6】初始化(InitializingBean、自定义 init)
    ↓
【阶段7】初始化后处理(AOP 代理创建)
    ↓
【阶段8】放入单例池,可供使用
    ↓
【阶段9】容器关闭时销毁(@PreDestroy、DisposableBean、自定义 destroy)
  • 1.1 阶段1:加载 BeanDefinition

    Spring 启动时,通过 BeanDefinitionReader 读取配置(XML、注解、Java Config),将类信息解析为 BeanDefinition 对象,注册到 BeanDefinitionRegistry(即 DefaultListableBeanFactory)。

    配置方式 对应的 Reader 示例
    XML XmlBeanDefinitionReader <bean id="userService" class="..."/>
    注解扫描 ClassPathBeanDefinitionScanner @ComponentScan("com.example")
    Java Config AnnotatedBeanDefinitionReader @Bean public UserService userService() {...}
  • 1.2 阶段2:BeanDefinition 合并与后置处理

    在实例化之前,Spring 会执行 MergedBeanDefinitionPostProcessorpostProcessMergedBeanDefinition() 方法,用于处理 @Autowired@Value@PostConstruct 等注解的元数据缓存:

    后置处理器 作用
    AutowiredAnnotationBeanPostProcessor 缓存 @Autowired@Value 注解的注入点
    CommonAnnotationBeanPostProcessor 缓存 @Resource@PostConstruct@PreDestroy 注解
    RequiredAnnotationBeanPostProcessor 处理 @Required 注解(已废弃)

    为什么要缓存? 避免每次创建 Bean 时都通过反射扫描注解,提升性能。

  • 1.3 阶段3:推断构造方法并实例化

    Spring 通过 AbstractAutowireCapableBeanFactory.createBeanInstance() 方法推断构造方法并创建实例。

    构造方法推断规则

    场景 推断结果
    只有一个无参构造 使用无参构造(默认)
    只有一个有参构造 使用唯一的有参构造
    多个构造方法,其中一个标注 @Autowired(required=true) 使用标注的构造方法
    多个构造方法,多个标注 @Autowired(required=false) 使用参数最多的构造方法
    多个构造方法,无 @Autowired 使用无参构造;若无无参构造,则报错
    java 复制代码
    @Service
    public class UserService {
        private final UserRepository userRepository;
        private final OrderRepository orderRepository;
    
        // Spring 会选择这个构造方法(参数最多且 @Autowired)
        @Autowired
        public UserService(UserRepository userRepository, OrderRepository orderRepository) {
            this.userRepository = userRepository;
            this.orderRepository = orderRepository;
        }
    
        public UserService(UserRepository userRepository) {
            this.userRepository = userRepository;
        }
    }

    构造方法参数解析 :按 byType 先查找,若同类型有多个 Bean,再按 byName 匹配。

  • 1.4 阶段4:依赖注入(属性填充)

    实例化后,Spring 执行 populateBean() 方法填充属性:

    1. InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation():允许在属性注入前修改 Bean 实例;
    2. InstantiationAwareBeanPostProcessor.postProcessProperties() :解析并注入 @Autowired@Value@Resource 等注解标记的属性;
    3. applyPropertyValues() :处理 XML 配置中的 <property> 标签。

    注入方式对比

    注入方式 注解 注入时机 特点
    构造器注入 无(或 @Autowired 实例化时 依赖必填,不可变,推荐
    Setter 注入 @Autowired 属性填充时 依赖可选,可重新设置
    字段注入 @Autowired 属性填充时 代码简洁,但测试困难,不推荐
  • 1.5 阶段5:初始化前处理(Aware 接口、@PostConstruct)

    属性填充完成后,进入 initializeBean() 方法,首先执行 Aware 接口:

    Aware 接口 注入内容 用途
    BeanNameAware Bean 的名称 获取自身 BeanName
    BeanFactoryAware BeanFactory 容器 获取容器引用
    ApplicationContextAware ApplicationContext 容器 获取应用上下文
    EnvironmentAware Environment 获取配置环境
    ResourceLoaderAware ResourceLoader 加载资源文件

    Aware 接口的执行顺序:按上述表格从上到下依次执行。

    然后执行 BeanPostProcessor.postProcessBeforeInitialization()

    后置处理器 作用
    ApplicationContextAwareProcessor 处理 ApplicationContextAware 等接口
    InitDestroyAnnotationBeanPostProcessor 调用 @PostConstruct 标注的方法

    @PostConstruct 的执行 :由 InitDestroyAnnotationBeanPostProcessor 处理,通过反射调用标注了 @PostConstruct 的方法。

  • 1.6 阶段6:初始化(InitializingBean、自定义 init)

    BeanPostProcessor.postProcessBeforeInitialization() 执行完毕后,进入真正的初始化阶段:

    复制代码
    【初始化顺序】
        ↓
    1. InitializingBean.afterPropertiesSet()
        ↓
    2. 自定义 init-method(@Bean(initMethod="...") 或 XML init-method)

    三层初始化回调的执行顺序

    顺序 回调方式 来源 说明
    1 @PostConstruct JSR-250 标准 最先执行,推荐
    2 InitializingBean.afterPropertiesSet() Spring 接口 次之,侵入性较强
    3 自定义 init-method 配置指定 最后执行,最灵活
    java 复制代码
    @Service
    public class UserService implements InitializingBean {
        @PostConstruct
        public void postConstruct() {
            System.out.println("1. @PostConstruct 执行");
        }
    
        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("2. InitializingBean 执行");
        }
    
        public void customInit() {
            System.out.println("3. 自定义 init-method 执行");
        }
    }
    
    // Java Config 中指定自定义 init
    @Bean(initMethod = "customInit")
    public UserService userService() {
        return new UserService();
    }
  • 1.7 阶段7:初始化后处理(AOP 代理创建)

    初始化完成后,执行 BeanPostProcessor.postProcessAfterInitialization()。这是 AOP 代理创建的关键时机

    后置处理器 作用
    AbstractAutoProxyCreator 检查 Bean 是否匹配切点,若匹配则创建代理对象

    为什么 AOP 代理在初始化后创建?

    因为代理对象需要包装完整的 Bean 实例(包括已注入的依赖和已执行的初始化逻辑)。如果在实例化时创建代理,后续的依赖注入和初始化会作用于代理对象,可能导致问题。

    代理创建后的 Bean 类型

    • JDK 代理:com.sun.proxy.$ProxyXX(实现目标接口)
    • CGLIB 代理:UserService$$EnhancerBySpringCGLIB(继承目标类)
  • 1.8 阶段8:放入单例池

    初始化完成后,Bean(或代理对象)被放入 DefaultSingletonBeanRegistry 的三级缓存:

    缓存级别 字段名 说明
    一级缓存 singletonObjects 存放完全初始化好的 Bean(成品)
    二级缓存 earlySingletonObjects 存放提前暴露的 Bean(半成品,用于解决循环依赖)
    三级缓存 singletonFactories 存放 Bean 的 ObjectFactory(用于创建代理对象)
  • 1.9 阶段9:销毁

    容器关闭时,执行销毁回调:

    顺序 回调方式 来源
    1 @PreDestroy JSR-250 标准
    2 DisposableBean.destroy() Spring 接口
    3 自定义 destroy-method 配置指定
    java 复制代码
    @Service
    public class UserService implements DisposableBean {
        @PreDestroy
        public void preDestroy() {
            System.out.println("1. @PreDestroy 执行");
        }
    
        @Override
        public void destroy() throws Exception {
            System.out.println("2. DisposableBean 执行");
        }
    
        public void customDestroy() {
            System.out.println("3. 自定义 destroy-method 执行");
        }
    }

2. 三级缓存解决循环依赖的源码级原理

循环依赖是 Spring Bean 生命周期中最经典的问题,Spring 通过三级缓存解决单例 Bean 的循环依赖。

  • 2.1 什么是循环依赖?

    java 复制代码
    @Service
    public class UserService {
        @Autowired
        private OrderService orderService;  // 依赖 OrderService
    }
    
    @Service
    public class OrderService {
        @Autowired
        private UserService userService;  // 依赖 UserService
    }

    创建 UserService 需要 OrderService,创建 OrderService 又需要 UserService,形成循环。

  • 2.2 三级缓存的结构与作用

    java 复制代码
    // DefaultSingletonBeanRegistry 源码
    public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
        // 一级缓存:成品单例池
        private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
        // 二级缓存:提前暴露的对象(半成品)
        private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
        // 三级缓存:单例工厂(用于创建代理对象)
        private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
    }
    缓存 存放内容 作用
    singletonObjects 完全初始化好的 Bean 最终使用的单例池
    earlySingletonObjects 已实例化但未初始化的 Bean 解决循环依赖,暴露半成品
    singletonFactories ObjectFactory(可生成 Bean 或代理) 延迟创建代理对象,解决循环依赖中的 AOP 代理问题
  • 2.3 循环依赖的解决流程

    UserServiceOrderServiceUserService 为例:

    复制代码
    1. getBean("userService")
       ↓
    2. 从 singletonObjects 查找 → 未找到
       ↓
    3. 实例化 UserService(调用构造方法)
       ↓
    4. 将 UserService 的 ObjectFactory 放入 singletonFactories(三级缓存)
       ↓
    5. 开始属性填充(populateBean),发现需要 OrderService
       ↓
    6. getBean("orderService")
       ↓
    7. 实例化 OrderService
       ↓
    8. 将 OrderService 的 ObjectFactory 放入 singletonFactories
       ↓
    9. 开始属性填充,发现需要 UserService
       ↓
    10. getBean("userService") ------ 再次获取 UserService
        ↓
    11. 从 singletonObjects 查找 → 未找到
        ↓
    12. 从 earlySingletonObjects 查找 → 未找到
        ↓
    13. 从 singletonFactories 查找 → 找到!调用 ObjectFactory.getObject()
        ↓
    14. 返回 UserService 的半成品(已实例化,未初始化)
        ↓
    15. OrderService 完成属性填充、初始化
        ↓
    16. OrderService 放入 singletonObjects
        ↓
    17. 回到 UserService 的属性填充,OrderService 已可用
        ↓
    18. UserService 完成初始化
        ↓
    19. UserService 放入 singletonObjects
  • 2.4 为什么需要三级缓存?二级缓存不够吗?

    核心原因:AOP 代理对象的创建时机问题

    如果只有二级缓存,循环依赖中的 Bean 在提前暴露时必须是最终形态(包括代理对象)。但 AOP 代理在初始化后(postProcessAfterInitialization)才创建,而循环依赖的属性填充发生在初始化之前。

    三级缓存的 ObjectFactory 作用 :延迟创建代理对象。当从三级缓存获取 Bean 时,ObjectFactory 会判断是否需要提前创建代理(通过 SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference()),确保暴露的是代理对象而非原始对象。

    java 复制代码
    // 三级缓存的 ObjectFactory 源码简化
    addSingletonFactory(beanName, () -> {
        // 如果有 AOP 代理,提前创建代理对象;否则返回原始对象
        return getEarlyBeanReference(beanName, mbd, bean);
    });
  • 2.5 循环依赖的局限

    场景 是否支持 原因
    单例 + 属性注入 ✅ 支持 三级缓存解决
    单例 + 构造器注入 ❌ 不支持 构造器注入时 Bean 尚未实例化,无法提前暴露
    原型(Prototype) ❌ 不支持 原型 Bean 不缓存,每次创建都是新实例

    构造器循环依赖的解决方案

    1. 改用 Setter/字段注入;
    2. 使用 @Lazy 延迟注入;
    3. 重构代码,消除循环依赖。

3. BeanPostProcessor 的作用与执行时机

BeanPostProcessor 是 Spring 提供的扩展接口,允许在 Bean 初始化的前后插入自定义逻辑。

接口 方法 执行时机 典型用途
BeanPostProcessor postProcessBeforeInitialization 初始化之前(Aware 之后) 自定义初始化前处理
BeanPostProcessor postProcessAfterInitialization 初始化之后 AOP 代理创建、自定义初始化后处理
InstantiationAwareBeanPostProcessor postProcessBeforeInstantiation 实例化之前 自定义实例化逻辑(如代理替换)
InstantiationAwareBeanPostProcessor postProcessAfterInstantiation 实例化之后 控制是否继续属性填充
InstantiationAwareBeanPostProcessor postProcessProperties 属性填充时 自定义属性注入(如 @Autowired 处理)
MergedBeanDefinitionPostProcessor postProcessMergedBeanDefinition BeanDefinition 合并后 缓存注解元数据

重要后置处理器汇总

后置处理器 实现的接口 核心作用
AutowiredAnnotationBeanPostProcessor InstantiationAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor 处理 @Autowired@Value
CommonAnnotationBeanPostProcessor InstantiationAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor 处理 @Resource@PostConstruct@PreDestroy
ApplicationContextAwareProcessor BeanPostProcessor 处理 Aware 接口
AbstractAutoProxyCreator InstantiationAwareBeanPostProcessor, BeanPostProcessor 创建 AOP 代理
RequiredAnnotationBeanPostProcessor MergedBeanDefinitionPostProcessor 处理 @Required

4. 生产环境避坑指南
  • 4.1 @PostConstruct 中不能使用 @Value 注入的配置?

    可以!@Value 的注入在属性填充阶段已完成,@PostConstruct 在属性填充之后执行,因此可以正常使用。

    java 复制代码
    @Service
    public class UserService {
        @Value("${server.port}")
        private String port;
    
        @PostConstruct
        public void init() {
            System.out.println("端口: " + port);  // ✅ 可以正常获取
        }
    }
  • 4.2 初始化方法中抛出异常会怎样?

    如果 @PostConstructafterPropertiesSet() 或自定义 init 方法抛出异常,Spring 会包装为 BeanCreationException,该 Bean 的创建失败,不会放入单例池。如果其他 Bean 依赖它,也会级联失败。

  • 4.3 不要在 BeanPostProcessor 中触发其他 Bean 的初始化

    如果在 BeanPostProcessor 中调用 getBean() 获取其他 Bean,可能导致该后置处理器尚未完全注册,引发不可预期的问题。

  • 4.4 AOP 代理对象的类型判断

    java 复制代码
    @Autowired
    private UserService userService;
    
    public void test() {
        // ❌ 错误:JDK 代理时 instanceof 判断失败
        if (userService instanceof UserServiceImpl) { ... }
    
        // ✅ 正确:使用 Spring 工具类
        if (AopUtils.isAopProxy(userService)) {
            Class<?> targetClass = AopProxyUtils.ultimateTargetClass(userService);
        }
    
        // ✅ 正确:判断接口
        if (userService instanceof UserService) { ... }
    }
  • 4.5 延迟初始化 @Lazy

    对于启动耗时较长的 Bean,可以使用 @Lazy 延迟初始化:

    java 复制代码
    @Service
    @Lazy
    public class HeavyService {
        // 只有在首次被注入或获取时才初始化
    }
  • 4.6 销毁方法中不要依赖其他 Bean

    容器关闭时,Bean 的销毁顺序不确定。如果在 destroy() 中调用其他 Bean 的方法,可能该 Bean 已销毁,导致空指针。


5. 面试官追问与高分回答模板
  • 追问 1:"说一下 Spring Bean 的生命周期"

    低分回答:"包括实例化、属性注入、初始化、使用、销毁几个阶段。"(太笼统,没有触及源码)

    高分回答

    "Spring Bean 的生命周期是一个完整的流水线,我从源码层面梳理:

    1. 加载 BeanDefinition :通过 BeanDefinitionReader 解析配置,注册到 BeanDefinitionRegistry
    2. BeanDefinition 合并与后置处理MergedBeanDefinitionPostProcessor 缓存 @Autowired@PostConstruct 等注解元数据;
    3. 推断构造方法并实例化 :根据 @Autowired 标注、参数数量等规则选择构造方法,通过反射创建实例;
    4. 依赖注入(populateBean)InstantiationAwareBeanPostProcessor 处理 @Autowired@Value@Resource 注入;
    5. 初始化前处理 :执行 Aware 接口(BeanNameAwareApplicationContextAware 等),然后 BeanPostProcessor.postProcessBeforeInitialization() 调用 @PostConstruct
    6. 初始化InitializingBean.afterPropertiesSet() → 自定义 init-method
    7. 初始化后处理BeanPostProcessor.postProcessAfterInitialization() 创建 AOP 代理;
    8. 放入单例池 :三级缓存(singletonObjects/earlySingletonObjects/singletonFactories);
    9. 销毁@PreDestroyDisposableBean.destroy() → 自定义 destroy-method

    其中最关键的是三级缓存解决循环依赖AOP 代理在初始化后创建这两个设计。"

  • 追问 2:"Spring 如何解决循环依赖?为什么需要三级缓存?"

    低分回答:"通过三级缓存解决,提前暴露半成品 Bean。"(没有解释为什么需要三级)

    高分回答

    "Spring 通过三级缓存解决单例 Bean 的属性注入循环依赖:

    缓存 内容 作用
    singletonObjects 成品 Bean 最终使用的单例池
    earlySingletonObjects 半成品 Bean 提前暴露,供循环依赖注入
    singletonFactories ObjectFactory 延迟创建代理对象

    为什么需要三级缓存?

    如果只有二级缓存,循环依赖中提前暴露的 Bean 必须是最终形态。但 AOP 代理在初始化后(postProcessAfterInitialization)才创建,而循环依赖的属性填充发生在初始化之前。

    三级缓存的 ObjectFactory 实现了延迟创建 :当从三级缓存获取 Bean 时,通过 getEarlyBeanReference() 判断是否需要提前创建代理对象,确保暴露的是代理对象而非原始对象。

    局限:只支持单例 + 属性注入的循环依赖。构造器注入和原型 Bean 的循环依赖不支持。"

  • 追问 3:"@PostConstruct、InitializingBean、自定义 init-method 的执行顺序是什么?"

    高分回答

    "执行顺序是:

    复制代码
    @PostConstruct → InitializingBean.afterPropertiesSet() → 自定义 init-method
    回调 来源 特点
    @PostConstruct JSR-250 标准 最先执行,推荐,无侵入
    InitializingBean Spring 接口 次之,侵入性较强,需实现接口
    init-method 配置指定 最后执行,最灵活,可在 XML 或 @Bean 中配置

    推荐优先使用 @PostConstruct,它是 Java 标准注解,不依赖 Spring 接口,代码更解耦。"

  • 追问 4:"构造器注入和字段注入有什么区别?Spring 推荐哪种?"

    高分回答

    "| 维度 | 构造器注入 | 字段注入 |

    |------|-----------|----------|

    | 依赖保证 | 必填,Bean 创建时就必须提供 | 可选,可能为 null |

    | 不可变性 | 可配合 final,实现不可变 | 不能加 final |

    | 测试友好性 | 高,可直接 new 并传参 | 低,需要反射或 Spring 容器 |

    | 循环依赖 | 不支持(可检测设计问题) | 支持(可能隐藏设计问题) |

    | NPE 风险 | 低,依赖必有 | 高,可能忘记注入 |

    Spring 官方推荐构造器注入(Spring 4+ 开始),原因:

    1. 依赖明确,不可变;
    2. 启动时就能发现循环依赖;
    3. 无需 @Autowired 注解(Spring 4.3+ 单构造器自动注入)。

    字段注入虽然代码简洁,但测试困难、可能隐藏循环依赖问题,不推荐。"

  • 追问 5:"BeanPostProcessor 和 BeanFactoryPostProcessor 有什么区别?"

    高分回答

    "| 维度 | BeanPostProcessor | BeanFactoryPostProcessor |

    |------|-------------------|-------------------------|

    | 作用对象 | Bean 实例 | BeanDefinition |

    | 执行时机 | Bean 实例化之后、初始化前后 | BeanDefinition 加载完成后、Bean 实例化之前 |

    | 典型用途 | AOP 代理创建、属性注入处理 | 修改 BeanDefinition(如 @ConfigurationProperties) |

    | 代表实现 | AbstractAutoProxyCreatorAutowiredAnnotationBeanPostProcessor | ConfigurationClassPostProcessorPropertySourcesPlaceholderConfigurer |

    BeanFactoryPostProcessor 在 Bean 实例化之前执行,可以修改 Bean 的定义(如修改作用域、属性值)。BeanPostProcessor 在 Bean 实例化之后执行,可以修改 Bean 实例(如创建代理、注入依赖)。

    典型应用:PropertySourcesPlaceholderConfigurer(处理 ${...} 占位符)是 BeanFactoryPostProcessor@Autowired 注入是 BeanPostProcessor。"

  • 追问 6:"AOP 代理为什么在初始化后创建,而不是实例化时?"

    高分回答

    "AOP 代理在初始化后(postProcessAfterInitialization)创建,原因有三:

    1. 依赖注入的完整性:代理对象需要包装完整的 Bean 实例,包括已注入的依赖。如果在实例化时创建代理,后续的属性填充会作用于代理对象,可能导致代理逻辑被覆盖或注入失败。
    2. 初始化回调的一致性@PostConstructInitializingBean 等初始化逻辑需要在代理对象上执行,确保代理能拦截这些回调(虽然通常不拦截)。
    3. 循环依赖的兼容性:如果 AOP 代理在实例化时创建,循环依赖中提前暴露的代理对象可能尚未完成依赖注入,导致其他 Bean 注入的是一个不完整的代理。

    但这也带来一个问题:循环依赖中的 Bean 需要提前暴露代理对象。Spring 通过三级缓存的 ObjectFactory.getEarlyBeanReference() 解决------在必要时提前创建代理,确保循环依赖注入的是代理对象而非原始对象。"


6. 方案选型速查表
业务场景 推荐方案 核心理由
初始化资源(连接池、线程池) @PostConstruct 标准注解,最先执行,无侵入
校验依赖完整性 InitializingBean 可抛出异常阻止 Bean 创建
复杂初始化逻辑 自定义 init-method 最灵活,可配置化
释放资源(关闭连接池) @PreDestroy 标准注解,最先执行
获取容器上下文 ApplicationContextAware Spring 提供的标准扩展点
动态修改 Bean 定义 BeanFactoryPostProcessor 实例化前修改 BeanDefinition
创建 AOP 代理 BeanPostProcessor 初始化后包装代理对象
解决构造器循环依赖 @Lazy 或重构 延迟注入或消除循环

💡 面试官想要的满分总结

Spring Bean 的生命周期是一个从"定义"到"销毁"的精密流水线,核心阶段包括:加载 BeanDefinition → 合并与后置处理 → 推断构造方法实例化 → 依赖注入 → 初始化前处理(Aware + @PostConstruct)→ 初始化(InitializingBean + 自定义 init)→ 初始化后处理(AOP 代理)→ 放入单例池 → 销毁。

理解生命周期必须抓住两个核心设计:三级缓存解决循环依赖BeanPostProcessor 扩展机制 。三级缓存中 singletonFactoriesObjectFactory 延迟创建代理对象,是解决循环依赖中 AOP 代理问题的关键;BeanPostProcessor 则在 Bean 创建的关键节点提供扩展能力,AOP 代理、依赖注入、注解处理都依赖于此。

工程实践中,优先使用构造器注入 (Spring 官方推荐),优先使用 @PostConstruct 做初始化 (标准注解、无侵入),警惕循环依赖 (构造器注入可提前暴露设计问题)。理解 BeanPostProcessorBeanFactoryPostProcessor 的区别------前者操作 Bean 实例,后者操作 Bean 定义------是区分初级和高级开发者的分水岭。


觉得对您有帮助,麻烦 点点关注啦 ,您的关注是我创作的最大动力~ 🎯

相关推荐
骑士雄师1 小时前
java面试题:jvm ,mybatis
java·jvm·mybatis
广州浮点FLOATLIC1 小时前
Creo 许可证利用率怎么优化:制造企业该先看共享规则,还是先看模块占用结构
java·开发语言
wuyk5551 小时前
21. 嵌入式面试避坑指南:sizeof 是关键字,不是函数!
c语言·开发语言·stm32·单片机·嵌入式硬件
2601_962440841 小时前
计算机毕业设计之jsp教室管理系统
java·开发语言·笔记·分布式·算法·课程设计·推荐算法
禅思院3 小时前
AI对话前端从入门到崩溃:一个长对话引发的五层优化战争【引子】
前端·面试·架构
带刺的坐椅3 小时前
用 ChatModel 构建 LLM 驱动的 Java 应用
java·ai·llm·solon·rag·chatmodel
赫媒派3 小时前
Gin 12年零破坏API,架构哲学如何练成?
后端·go·gin
fliter4 小时前
Arborium:把 tree-sitter 语法高亮打包成 Rust 文档生态的基础设施
后端
张三丰24 小时前
不会写代码的高管用Claude Code两天上线新程序,工程师接手后发现:一个Bug,让AI一天烧掉一个月服务器费!
后端