spring三级缓存

在Spring框架中,三级缓存机制是其解决循环依赖问题的关键设计之一,特别是在处理单例bean的循环依赖时。这三级缓存分别是:

  1. beanDefinitionMap

    • 这是第一级缓存,主要用于存储所有Bean的定义信息BeanDefinition对象)。当Spring容器启动并解析配置(如XML配置或注解)时,会将每个Bean的定义加载到这个Map中。BeanDefinition包含了类名、作用域、依赖关系等元数据信息。
  2. singletonObjects

    • 第二级缓存,用于存储完全初始化完毕的单例Bean实例。当一个单例Bean完成了实例化和所有初始化过程(包括属性注入、初始化方法调用等),它会被放置到这里。从这个缓存中取出的Bean是完全可用的,可以直接注入到其他需要它的Bean中。
  3. singletonFactories

    • 这是第三级缓存,存放的是生产Bean实例的工厂对象(ObjectFactory)。当一个单例Bean被创建但尚未完成其全部初始化过程时,会先放入这个缓存中。使用工厂对象的好处在于,它可以延后Bean的完整初始化过程,直到真正需要使用Bean时才进行最后的初始化步骤。这对于解决循环依赖至关重要,因为它允许Spring在遇到循环依赖时,能够返回一个可用来创建实例但尚未完全初始化的工厂引用,从而打破了循环,后续再完成剩余的初始化步骤。

三级缓存的作用

  • 解决循环依赖:通过这三级缓存,Spring能够在实例化Bean的过程中,即使遇到循环依赖的情况,也能够确保每个Bean至少有一个可注入的引用,哪怕这个引用还未完全初始化。这样,Spring就可以继续完成依赖链上的其他Bean的创建,最终解决循环依赖问题。
  • 提高性能:避免了不必要的重复实例化,特别是对于单例Bean,一旦创建就可以重复利用。
  • 支持AOP代理:在处理包含AOP代理的循环依赖时,三级缓存的设计尤为重要,它确保了即使是在AOP代理创建过程中也能正确处理依赖关系,避免了直接使用未代理的对象。

举例说明:

@Service
public class ServiceA {
    private ServiceB serviceB;

    @Autowired
    public void setServiceB(ServiceB serviceB) {
        this.serviceB = serviceB;
    }
}

@Service
public class ServiceB {
    private ServiceA serviceA;

    @Autowired
    public void setServiceA(ServiceA serviceA) {
        this.serviceA = serviceA;
    }
}

处理过程:

BeanDefinitionMap:
Spring启动时,首先读取配置,发现ServiceA和ServiceB的定义,将它们的BeanDefinition分别加入到beanDefinitionMap中。

创建ServiceA:
Spring开始创建ServiceA的实例,此时ServiceA依赖于ServiceB,但ServiceB尚未创建。
因为是单例模式,Spring尝试从singletonObjects缓存中获取ServiceB,但未找到,因为ServiceB还没创建;这时将ServiceA实例(已经创建但未实例化)包装进ObjectFactory【通过SingletonBeanRegistry.getSingleton(String beanName, ObjectFactory<?> singletonFactory)方法包装】,将ObjectFactory放入singletonFactories三级缓存中。

创建ServiceB(同时处理循环依赖):
接着Spring转而创建ServiceB实例,ServiceB又依赖于ServiceA。
Spring再次尝试从singletonObjects获取ServiceA,但因为ServiceA的创建尚未完成,它会发现ServiceA存在于singletonFactories缓存中作为一个半成品(即ObjectFactory),从singletonFactories中获取到代表ServiceAObjectFactory【ObjectFactory#getObject】获取到ServiceA实例,并注入到ServiceB中,这样就打破了循环依赖的死锁。

@FunctionalInterface
public interface ObjectFactory<T> {
    T getObject() throws BeansException;
}

完成初始化:随着循环依赖被临时解决,Spring继续完成ServiceAServiceB的初始化,包括完成有依赖注入、调用初始化方法等。最终,当所有步骤完成,两个Bean都会被放入singletonObjects缓存,作为完全初始化的单例实例。

简而言之:分别创建A和B两个对象的时候,都会创建对应的ObjectFactory对象放在三级缓存中,然后依赖对象的时候,会先从二级缓存中找需要的对象,如果找不到,就会去三级缓存中找到该对象的ObjectFactory,然后通过该ObjectFactory对象中返回需要的A或者B对象;最后将初始化后的对象放入二级缓存中。

  • 11
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Addison_Wang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值