001. Spring 是如何解决循环依赖的?
答:
什么是循环依赖?
循环依赖指两个或多个 Bean 相互依赖(如 A 依赖 B,B 依赖 A)。
在创建A时,初始化A时需要注入B,那么就需要去创建B;
在创建B时,初始化B时需要注入A,那么就需要去创建A;
此时就形成了循环依赖(程序会死等),最终导致 Bean 创建失败。
如何解决循环依赖问题?
Spring 通过拆分Bean的创建过程,将实例化和初始化分开。
- 当创建A时,先实例化A,再对A进行初始化,此时发现需要注入实例B;
- Spring此时会将实例化但未完成初始化的A存到缓存中(此处引入三级缓存概念),此时的A是可以被引用的,但并不完整(因为没有完成初始化,b还没有注入);
- 此时Spring会去创建B,先实例化B,然后再对B进行初始化,此时发现需要注入实例A;
- 此时Spring会把存入缓存的A注入B中(虽然A未完成初始化,但是可以先行注入B,后面再完成A的初始化也是可以的),此时B就创建完成了;
- 当B的实例创建完成后,Spring会回到对A实例的初始化步骤来,将成功创建的B注入到A中,此时A也完成了初始化。
- 即此时完成了对A和B的实例化和初始化操作,成功解决了循环依赖的问题。
三级缓存是什么?如何被使用的?
这里存在三级缓存的概念,Spring寻找实例化好的bean时会按照一级、二级、三级的顺序依次查找。
注意:三级缓存中不会出现相同名称的bean,当上一级存入相同名称的bean时,下一级同名的bean会被自动删除。
一级缓存存放的是:实例化完成且初始化完成的实例;
二级缓存存放的是:实例化完成但初始化未完成的实例;
三级缓存存放的是:存放Bean 的工厂对象(ObjectFactory),用来生成早期的bean或其代理对象,同时保证三级缓存中不会出现同名的bean实例。
002. Spring Bean 的生命周期
答:
Spring 的完整生命周期(按执行顺序)
实例化 -> 属性注入 -> 生命周期回调 -> 初始化 -> 使用 -> 销毁
各核心阶段的作用
- 实例化:Spring 通过反射创建 Bean 的实例;
- 属性注入:Spring 将配置文件或注解中定义的属性值(如
@Autowired注入的依赖)赋值给 Bean 实例(此处会产生循环依赖问题); - 生命周期回调(初始化前):Bean 实现 Aware 接口的回调,如
BeanNameAware(获取 Bean 的 id)、BeanFactoryAware(获取 BeanFactory 容器)、ApplicationContextAware(获取 ApplicationContext 上下文); - 初始化:执行自定义初始化逻辑,优先级为:
@PostConstruct注解方法
->InitializingBean接口的afterPropertiesSet()
-> XML 配置的init-method属性指定方法。 - 使用:Bean 实例存入 Spring 容器,供应用程序通过
getBean()或依赖注入方法使用; - 销毁:容器关闭时执行自定义销毁逻辑,优先级:
@PreDestory注解方法
->DisposableBean接口的destory()
-> XML 配置的destory-method属性指定方法。
关键接口/注解说明
- Aware 系列接口:用于 Bean 获取容器相关信息,无需手动调用,容器自动触发;
- 初始化相关:
@PostConstrut(注解式,最常用)、InitializingBean(接口式)、init-method(XML 配置式); - 销毁相关:
@PreDestory(注解式)、DisposableBean(接口式)、destroy-method(XML 配置式)。

国内还是各种 java 招聘。
但是竞争更激烈了,就业环境也更难了。
今天刚失业,没办法,只能把八股文再拾起来了。
是的,挺难的。我也在写 java。