面试专题--Spring Bean的生命周期、三级缓存
2025-02-21 10:52:54 0 举报
在Spring框架中,Bean的生命周期管理是其核心功能之一。从初始化到销毁的整个过程中,Spring提供了丰富的扩展点供开发者定制Bean的行为。首先,在Bean的初始化阶段,Spring容器会先通过解析XML配置或注解扫描创建Bean的定义。随后,使用三级缓存机制确保单例模式下Bean的唯一性和懒加载。 三级缓存主要包含了: 1. 一级缓存:存放完全初始化好的Bean实例。 2. 二级缓存:存放早期的Bean引用,主要用于解决循环依赖。 3. 三级缓存:存放生成Bean的工厂对象,用于解决复杂的依赖问题。 在Bean的生命周期中,多个关键的接口会被顺序调用,如`BeanNameAware`、`BeanFactoryAware`、`ApplicationContextAware`等用于Bean设置依赖的回调接口,以及`@PostConstruct`注解标记的方法用于执行初始化前的逻辑。之后,Bean的实例会被包装在BeanWrapper中,然后进入一系列生命周期的处理,例如处理BeanPostProcessor前后的逻辑。 最终,当应用关闭时,容器中的所有Bean将会被销毁,此时会调用`DisposableBean`接口中定义的destroy方法,和通过`@PreDestroy`注解标记的方法,从而确保资源得到正确释放。整个流程体现了Spring Bean生命周期的高度可配置性和拓展性。
作者其他创作
大纲/内容
五: 1:在进行属性填充时,发现依赖了B对象,执行 AbstracBeanFactory.getBean 方法,尝试获取B对象。参考上面步骤一到四。 2:执行到B对象的属性填充时,发现依赖了A对象,执行 AbstracBeanFactory.getBean 方法,尝试获取 A 对象。 到一级缓存 singletonObjects 中找,未找到; 到二级缓存 earlySingletonObjects 中找,未找到; 到三级缓存 singletonFactories 中找,找到了A对象的 singletonFactories, 调用 ObjectFactory 的 getObject 方法获取A对象的引用, ObjectFactory 内部调用了 AbstractAutowireCapableBeanFactory 的 getEarlyBeanReference ,获取到 A 的早期对象, 将A的早期对象放入二级缓存 earlySingletonObjects 中,并将三级缓存 singletonFactories 中 A 对象移除 3:B 拿到 A 对象之后,B的属性填充完毕,B初始化完成,方法 return 到 DefaultSingletonBeanRegistry 的 getSingleton 的重载方法时, 调用 DefaultSingletonBeanRegistry的 addSingleton 方法,将B对象放入一级缓存,并将B从二三级缓存中移除(虽然已经没有了)。 4: 这样在 return回 A 的流程,第四大步第3小步 ,将 A 依赖的 B 属性填充完整,此时 A 也填充完毕,初始化完成,方法继续 return 到 A 流 程的 DefaultSingletonBeanRegistry 的 getSingleton 的重载方法时,5:调用 DefaultSingletonBeanRegistry 的 addSingleton 方法,将 A 对象放入一级缓存,并将A从二级缓存中移除 6: A 和 B 初始化完成。
Spring 三级缓存
初始化完成
四:AbstractAutowireCapableBeanFactory.class 1:在 reateBean 方法中,调用 doCreateBean方法,实际执行创建A对象。 2: 实例化A对象,调用 DefaultSingletonBeanRegistry 的 addSingletonFactory 方法, 将 ObjectFactory 对象放入三级缓存 singletonFactories 中,设置A对象已经开始注册。 3:调用 populateBean 方法,对A对象进行属性填充。
Spring 三级缓存 Map
将Bean从三级缓存移动到一级缓存
一: 1:SpringBoot项目启动时,执行run方法中的 refreshContext(context); 2:调用 this.refresh(context); 3:调用 AbstractApplicationContext的refresh()方法,开始初始化BeanFactory。
开始
调用自定义的初始化方法
Spring Bean的创建过程
●Spring对bean进行实例化;●Spring将值和bean的引用注入到bean对应的属性中;●如果bean实现了BeanNameAware接口,Spring将bean的ID传递给setBean-Name()方法;●如果bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入;●如果bean实现了ApplicationContextAware接口,Spring将调用setApplicationContext()方法,将bean所在的应用上下文的引用传入进来;●如果bean实现了BeanPostProcessor接口, Spring调用它们的post-ProcessBeforeInitialization()方法;●如果bean实现了InitializingBean接口,Spring调用它们的after-PropertiesSet()方法。类似地,如果bean使用initmethod声明了初始化方法,该方法也会被调用;●如果bean实现了BeanPostProcessor接口,Spring调用它们的post-ProcessAfterInitialization()方法;●此时,bean已经准备就绪,可以被应用程序使用了,它们将一直驻留在应用上下文中,直到该应用上下文被销毁;●如果bean实现了DisposableBean接口,Spring将调用它的destroy()接口方法。同样,如果bean使用destroy-method声明了销毁方法,该方法也会被调用。
BeanFactoryAware的setBeanFactory()方法
Bean是否存在于一级缓存?
是
否
实例化
创建Bean,放入三级缓存,并尝试放入二级缓存
二: 1:在 refresh 步骤中,执行到this.finishBeanFactoryInitialization(beanFactory),开始完成 Bean 工厂初始化。
Bean是否存在于二级缓存?
结束
填充属性
ApplicationContextAware的setApplicationContext()方法
不管有没有循环依赖,Spring 都会使用三级缓存机制,但是没有循环依赖的情况下,三级缓存 主要用于代理对象的提前暴露,尤其是在 AOP 等场景下。那么,如果没有循环依赖,在三级缓存中存放 Bean 后,什么时候将它移入二级缓存(earlySingletonObjects)和一级缓存(singletonObjects)呢?这个过程通常遵循以下几个步骤。从三级缓存到二级缓存1:当 Bean 的 ObjectFactory 被调用来生成一个早期实例(通常是代理对象)时,它会被放入 earlySingletonObjects。2:如果这个 Bean 被其他正在初始化的 Bean 依赖,它就会从二级缓存(earlySingletonObjects)中获取到并继续使用。从二级缓存到一级缓存1:在 Bean 的初始化过程(比如执行 @PostConstruct 方法或 InitializingBean 的 afterPropertiesSet())完成后,Spring 会将这个完全初始化的 Bean 从 earlySingletonObjects 移到 singletonObjects 中。如果对象 A, 没有循环依赖,没有代理需求,流程如下:1:singletonFactories 中存放 A 的工厂对象。2:调用填充属性方法时工厂对象创建 A 的早期对象。3:调用初始化方法完成所有初始化后(如 afterPropertiesSet() 执行完毕),将 A 直接放入 singletonObjects 中,表示 A 完全初始化。同时删除singletonFactories 中存放 A 的工厂对象。特点:不会经过 earlySingletonObjects(除非有 AOP 或循环依赖)。假设对象 A,没有循环依赖,只有代理需求,流程如下:1:singletonFactories 中存放 A 的工厂对象。2:调用填充属性方法时工厂对象创建 A 的早期代理对象,并把A的早期代理对象放入 earlySingletonObjects 缓存中,同时删除 singletonFactories 中A的早期代理对象。3:调用初始化方法完成所有初始化后,将 A 放入 singletonObjects 中,同时删除 singletonFactories 中的A,表示 A 完全初始化。同时删除singletonFactories 中存放 A 的工厂对象。特点:需要经过 earlySingletonObjects 。如果对象 A 和 B 循环依赖,它在 Spring 的三级缓存中将按照以下步骤工作:参考:Bean A 和 Bean B 相互依赖的场景
调用自定义的销毁方法
AOP实现
如果A或者B存在AOP,需要返回代理对象,这操作是在第五步中第2小步的 AbstractAutowireCapableBeanFactory 的 getEarlyBeanReference 中完成的,B尝试获取A的时候,触发了这个方法,如果A需要被代理,则是在这个方法中执行的,这个方法最终返回了一个代理对象,并将这个对象以A的名义放入了二级缓存。
尝试从二级缓存获取Bean
SpringApplication.class public ConfigurableApplicationContext run(String... args) { this.refreshContext(context); } private void refreshContext(ConfigurableApplicationContext context) { this.refresh(context); } protected void refresh(ConfigurableApplicationContext applicationContext) { applicationContext.refresh(); }
Spring Bean生命周期
调用DisposableBean的destroy()方法
Bean A 和 Bean B 相互依赖的场景
从一级缓存获取Bean
BeanPostProcessor的post-ProcessAfterInitialization()方法
InitializingBean的after-PropertiesSet()方法
从二级缓存获取Bean并放入一级缓存
BeanPostProcessor的post-ProcessBeforeInitialization()方法
BeanNameAware的setBean-Name()方法
初始化一级缓存
三 1:在 getBean 方法中,执行 doGetBean 方法,尝试获取A对象。 2:在 doGetBean 方法中执行 DefaultSingletonBeanRegistry 的 getSingleton 方法,尝试从缓存(一级二级三级)中获取A对象的单例对象缓存 到一级缓存 singletonObjects 中找,未找到; 到二级缓存 earlySingletonObjects 中找,未找到; 到三级缓存 singletonFactories 中找,未找到; 3:再次执行 DefaultSingletonBeanRegistry 的 getSingleton 重载方法,传入lamda表达式形式的ObjectFactory对象,内部调用 AbstractAutowireCapableBeanFactory 的 createBean 方法,尝试创建A对象。
0 条评论
下一页