One minute
Spring缓存三级缓存机制
Spring三级缓存
想起之前面试被问到的一个回答的不好的基础题,“spring如何解决循环依赖的?”
因为并没有真正理解spring缓存机制和作用,所以早起看过后就忘了,现在重新复习下。
跟着GPT一步步学 Spring 三级缓存。
什么是spring三级缓存
spring三级缓存,是spring框架用于解决单例作用域Bean的循环依赖问题的一种机制。
- Singleton Objects Cache 单例对象缓存: 这个缓存存储已经完全初始化的单例Bean. 这个阶段,所有依赖已经注入,所有生命周期方法已经执行完毕。当一个bean被请求时,spring首先会从这个缓存中获取Bean。
- Early Singleton Objects Cache 早期单例对象缓存:这个缓存存储已经实例化,但未完全初始化的Bean。相比 Singleton Objects Cache, 它的依赖注入和生命周期方法并没完成。 当Singleton Objects Cache中找不到Bean时候,会去这里找Bean, 以解决循环依赖。需要注意的是,如果是构造函数的注入,那么实例化阶段就要注入,此时有循环依赖是无法解决的。
- Singleton Factories Cache 单例工厂缓存。这个缓存存储了创建bean的工厂对象。当在Early Singleton Objects Cache 也知道不到Bean, spring会尝试从这个缓存中获取工厂对象创建一个提前暴露的Bean实例。这个实例被放入到 Early Singleton Objects Cache 中, 以解决循环依赖的问题。
根据以上介绍我们知道,一级缓存存的是满状态的Bean, 二级缓存存的是构建好,但没初始化话好的Bean,三级缓存存的是单例工厂缓存。 无论何种方式,要装配都要先有实例才能依据实例来进行装配,所以如果是构造函数注入的循环依赖,spring三级缓存是无法解决的。
Spring Bean作用域
了解了三级缓存后,我们知道以上都是对单例bean的操作,那么来复习下spring作用域有哪些。
- Singleton 单例。整个spring容器中,一个类的单例Bean实例只会被创建一次。这是Spring默认的作用域
- Prototype 原型。每次请求一个Bean时候,都会创建一个新的实例。
- Request 请求。每一个HTTP请求的生命周期内,一个Bean的实例只会被创建一次。这个作用于仅适用于Web应用程序。
- Session 会话。在一个HTTP会话的生命周期内,一个Bean的实例只会被创建一次。这个做用户仅适用于Web应用程序。
- Application 应用。 在一个ServletContext的生命周期内,一个Bean的实例只会被创建一次。这个作用域仅适用于Web应用程序。
Spring Bean生命周期
既然说到了注入,就来了解下注入时候spring做了哪些事。
Spring Bean 生命周期简化概述:
- Spring容器启动
- Bean 定义被读取,Spring确定Bean的依赖关系。
- 实例化Bean, 调用构造函数。
- Setter 注入:spring 容器注入带有 @Autowired 注解的依赖项
- 如果实现了 BeanNameAware 、BeanFactoryAware 等接口,调用相应的方法。
- 如果Bean实现了BeanPostProcessor接口,调用postProcessBeforeInitialization方法
- 初始化Bean, 这可能包括调用 @PostConstruct 注解的方法、调用afterPropertiesSet方法(如果实现了InitializingBean接口) 或调用自定义的初始化方法 (通过@Bean(initMethod=“customInit”)指定)。
- 如果Bean实现了BeanPostProcessor接口,调用 postProcessAfterInitialization方法
- Bean 现在已经准备好使用。
- 当应用程序关闭或Spring容器被销毁时,执行清理操作,包括调用@PreDestory注解的方法,调用destroy方法(如果实现了DisposableBean接口) 或调用自定义的销毁方法(通过@Bean(destroyMethod=“customDestroy”)指定)
graph TD;
A[Spring容器启动]-->B[读取Bean定义,确定Bean依赖关系]
B --> C[实例化Bean,调用构造函数]
C --> D[Setter注入 \ 字段注入]
D --> E{是否实现BeanPostProcessor}
E -->|是| F[调用postProcessBeforeInitialization]
E -->|否| G[初始化Bean,PostConstruct注解方法,自定义初始化方法]
F --> G
G -->|如果实现| H[BeanPostProcessor的postProcessAfterInitialization]
H --> I[Bean准备好了]
I --> J[spring容器销毁,preDestroy, destory, customDestroy]
J --> K[结束]
Spring提供了哪些依赖注入方式:
- 构造器注入 (Constructor Injection)
- Setter注入 (Setter Injection)
- 字段注入 (Field Injection)
简单代码示例:
构造器注入
@Component
public class A {
private B b;
@Autowired
public A(B b) {
this.b = b;
}
}
Setter注入
@Component
public class A {
private B b;
@Autowired
public void setB(B b) {
this.b = b;
}
}
3. 字段注入
public class A {
@Autowired
private B b;
}
实际开发中,构造器通常是首选依赖注入方式,因为可以确保Bean在创建时候就完全初始化,避免潜在空指针异常。Setter注入和字段注入虽然某些生活更方便,但会导致Bean处于不完全初始化状态。所以优先考虑构造器注入。
Read other posts