spring bean的三级缓存原理

这篇具有很好参考价值的文章主要介绍了spring bean的三级缓存原理。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

当我们在使用 Spring 框架时,通常会遇到循环依赖、AOP 代理等问题。为了解决这些问题,Spring 引入了三级缓存机制,
即 singletonObjects、earlySingletonObjects 和 singletonFactories 三个缓存。本文将详细介绍 Spring 三级缓存的原理和作用。

1. Spring 三级缓存的作用

在 Spring 框架中,Bean 实例化和依赖注入是非常重要的步骤。在这个过程中,循环依赖和 AOP 代理是两个比较常见的问题,而三级缓存机制就是为了解决这些问题而设计的。
具体来说,Spring 的三级缓存的作用如下:

解决循环依赖问题:当一个 Bean 的创建依赖于其他 Bean 的创建时,就可能会出现循环依赖的问题。Spring 的三级缓存机制可以通过代理对象的方式来解决循环依赖问题。

确保单例模式:Spring 默认使用单例模式来管理 Bean,即同一个 Bean 在应用程序的整个生命周期中只被创建一次。而三级缓存机制可以确保单例模式的正确实现。

提高 Spring 的性能:使用缓存可以提高 Spring 的性能,因为缓存可以避免重复创建 Bean 实例的开销。

解决 AOP 代理对象和目标对象名称冲突问题:在使用 AOP 的时候,如果将目标对象和代理对象都缓存在 singletonObjects 缓存中,就可能会出现两个对象名称相同的问题,这可能会导致一些奇怪的问题出现,比如说无法注入正确的对象。因此,Spring 引入了 singletonFactories 缓存来解决这个问题。

2. Spring 三级缓存的实现原理

在 Spring 中,Bean 的创建过程可以分为以下几个阶段:
解析 BeanDefinition:读取配置文件或者注解等方式,将 BeanDefinition 解析成对象。
创建 Bean 实例:根据 BeanDefinition 中的信息,创建 Bean 实例,并进行属性注入和初始化等操作。
将 Bean 实例放入缓存:将创建好的 Bean 实例放入 Spring 的缓存中,以供后续使用。
在这个过程中,Spring 的三级缓存机制就发挥了重要的作用。下面我们来分别介绍三级缓存的作用和实现原理。
2.1 singletonObjects 缓存
singletonObjects 缓存是 Spring 中最常用的一个缓存,用于存储已经创建好的 Bean 实例。这个缓存是一个 ConcurrentHashMap 类型的对象,它将 Bean 的名称作为 key,将 Bean 实例作为 value。
在使用 singletonObjects 缓存时
,在使用 singletonObjects 缓存时,Spring 首先会从缓存中尝试获取 Bean 实例。如果缓存中不存在对应的 Bean 实例,那么就会继续执行创建 Bean 实例的操作。在创建 Bean 实例的过程中,如果发现当前 Bean 已经被创建了,则会从 singletonObjects 缓存中获取该 Bean 实例并返回。
在默认情况下,singletonObjects 缓存的存储策略是“早期曝光”。也就是说,当 Bean 实例被创建后,就会被立即放入 singletonObjects 缓存中。这样可以确保在创建 Bean 实例时就能够获取到该实例的引用,避免了出现循环依赖问题。
2.2 earlySingletonObjects 缓存
earlySingletonObjects 缓存是 Spring 中比较少用到的一个缓存。它的作用是存储“早期曝光”的 Bean 实例,也就是在创建 Bean 实例时尚未完成依赖注入的 Bean 实例。
在创建 Bean 实例的过程中,如果发现该 Bean 依赖于另外一个还未创建完成的 Bean,那么就会将当前 Bean 实例放入 earlySingletonObjects 缓存中。等到该依赖的 Bean 实例创建完成后,Spring 就会将 earlySingletonObjects 缓存中的 Bean 实例进行依赖注入,并将其移动到 singletonObjects 缓存中。
2.3 singletonFactories 缓存
singletonFactories 缓存是 Spring 中专门为解决 AOP 代理对象和目标对象名称冲突问题而设计的缓存。在使用 AOP 的时候,如果将目标对象和代理对象都缓存在 singletonObjects 缓存中,就可能会出现两个对象名称相同的问题,这可能会导致一些奇怪的问题出现,比如说无法注入正确的对象。
为了解决这个问题,Spring 引入了 singletonFactories 缓存。在创建代理对象时,Spring 首先会创建一个 ObjectFactory 对象,并将其放入 singletonFactories 缓存中。等到需要使用代理对象时,Spring 就会调用 ObjectFactory 的 getObject() 方法来创建代理对象,并将其放入 singletonObjects 缓存中。

3. 三级缓存的使用示例

为了更好地理解 Spring 的三级缓存机制,下面我们来看一个简单的示例。
假设我们有一个名为 User 的 Bean,它依赖于另一个名为 Role 的 Bean。此时,Spring 的 Bean 创建过程可以分为以下几个阶段:
解析 User 和 Role 的 BeanDefinition,将其解析为对象。
创建 Role Bean 实例,并放入 singletonObjects 缓存中。
创建 User Bean 实例,发现它依赖于 Role Bean,将 User 实例放入 earlySingletonObjects 缓存中。
创建 Role Bean 实例的代理对象,并将代理对象
放入 singletonObjects 缓存中。
将 Role Bean 实例注入到 User Bean 实例中。
将 User 实例从 earlySingletonObjects 缓存中移动到 singletonObjects 缓存中。
在这个过程中,三级缓存的作用可以概括为:
singletonObjects 缓存用于存储创建完成并已经进行了依赖注入的 Bean 实例。
earlySingletonObjects 缓存用于存储已经创建但尚未进行依赖注入的 Bean 实例。
singletonFactories 缓存用于存储 AOP 代理对象和目标对象名称相同时的代理工厂对象。
三级缓存的使用示例代码如下:

@Component
public class User {
 
    @Autowired
    private Role role;



    // 省略其他代码
}
}



@Component
public class Role {



    // 省略其他代码
}
}



@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AppConfig {



    @Bean
    public Role role() {
 
        return new Role();
 
    }



    @Bean
    public User user() {
 
        return new User();
 
    }



    @Bean
    public RoleInterceptor roleInterceptor() {
 
        return new RoleInterceptor();
 
    }



    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
 
        return new DefaultAdvisorAutoProxyCreator();
 
    }



    @Bean
    public ProxyFactoryBean roleProxy() {
 
        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
 
        proxyFactoryBean.setTarget(role());
 
        proxyFactoryBean.addAdvice(roleInterceptor());
 
        return proxyFactoryBean;
 
    }
}
}



public class RoleInterceptor implements MethodInterceptor {
 
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
 
        System.out.println("before");
 
        Object result = invocation.proceed();
 
        System.out.println("after");
 
        return result;
 
    }
}
}



public class Main {
 
    public static void main(String[] args) {
 
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
 
        User user = context.getBean(User.class);
 
    }
}
}

在上面的代码中,我们创建了一个 User Bean,它依赖于 Role Bean。我们还创建了一个 RoleInterceptor 来作为 Role Bean 的 AOP 拦截器,以及一个 Role Bean 的代理对象。
在这个例子中,如果我们将三级缓存的某一级去掉,就可能会导致 Bean 创建失败或者出现一些奇怪的问题,比如说:
如果没有 earlySingletonObjects 缓存,就可能会出现循环依赖问题,导致 Bean 创建失败。
如果没有 singletonFactories 缓存,就可能会出现两个对象名称相同的问题,导致注入错误的对象或者无法注入对象。
因此,Spring 的三级缓存机制可以很好地保证 Bean 的创建和依赖注入的正确性,同时也能够有效地避免一些奇怪的问题出现。文章来源地址https://www.toymoban.com/news/detail-440206.html

到了这里,关于spring bean的三级缓存原理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring三级缓存详解

    Spring三级缓存 是为了解决 对象间的循环依赖 问题。 A依赖B,B依赖A,这就是一个简单的循环依赖。 我们来先看看三级缓存的源码。 (1)查看“获取Bean”的源码,注意getSingleton()方法。 (2)“添加到第1级缓存”的源码: (3)“添加到第3级缓存”的源码: (4)“创建Be

    2024年02月07日
    浏览(60)
  • Spring三级缓存

    重点AOP作用于代理对象,方法中调用其余方法的注解需要将本类注入进去。 当AService出现了循环依赖的情况下----AService提前进行AOP 0.creatingSet.add(\\\'aService\\\') 1.class -实例化得到Aservice原始对象--提前进行AOP---AService代理对象---Mapbe anMap, Aservice代理对象 2.给bService属性赋值---从单例池

    2024年01月21日
    浏览(38)
  • 【Spring】三级缓存

    结合文章:循环依赖 测试代码如下: 执行refresh 方法 执行finishBeanFactoryInitialization 方法 执行preInstantiateSingletons 方法 实际上就是通过 doGetBean ,先进行 bean-a 的初始化 去缓存查看时候有 bean - a 实际上就是通过双重校验锁,去查看一级缓存中是否有 bean-a 并且没有在创建中 ,所

    2024年02月21日
    浏览(83)
  • 三级缓存---解决 Spring 循环依赖

    首先,什么是循环依赖?这个其实好理解,就是两个 Bean 互相依赖,类似下面这样: \\\"\\\"\\\" \\\"\\\"\\\" AService 和 BService 互相依赖: 一般来说,循环依赖有三种不同的形态,上面就是其中一种。 另外两种分别是三者依赖,如下图: 这种循环依赖一般隐藏比较深,不易发觉。 还有自我依

    2024年02月16日
    浏览(44)
  • spring解决循环依赖的三级缓存

    实例化,对应方法:AbstractAutowireCapableBeanFactory中的createBeanInstance方法,简单理解就是new了一个对象。 属性注入,对应方法:AbstractAutowireCapableBeanFactory的populateBean方法,为实例化中new出来的对象填充属性和注入依赖。 初始化,对应方法:AbstractAutowireCapableBeanFactory的initialize

    2024年02月03日
    浏览(40)
  • Spring——三级缓存解决循环依赖详解

    就是在Bean生成流程中保存Bean对象三种形态的三个Map集合,如下: 用来解决什么问题? 这个大家应该熟知了,就是循环依赖 什么是循环依赖? 就像下面这样,AService 中注入了BService ,而BService 中又注入了AService ,这就是循环依赖 这几个问题我们结合源码来一起看一下 : 三级

    2024年02月03日
    浏览(38)
  • [Spring] 三级缓存解决循环依赖详解

    注册一个bean对象的过程: Spring扫描class得到BeanDefinition – 根据得到的BeanDefinition去生成bean – 现根据class推断构造方法 – 根据推断出来的构造方法,反射,得到一个对象 – 填充初始对象中的属性(依赖注入) – 如果原始对象种的某个方法被AOP了,那么要根据原始对象生成一

    2024年02月15日
    浏览(40)
  • 【Spring框架全系列】方法注解@Bean的使用

    📬📬哈喽,大家好,我是小浪。上篇博客我们介绍了五大类注解的使用方法,以及如何解决Spring使用五大类注解生成bean-Name的问题;那么,谈到如何更简单的读取和存储对象,这里我们还需要介绍另外一个\\\"方法注解@Bean\\\"的使用,快来一起学习叭!🛳🛳 📲目录 一、如何使

    2024年02月04日
    浏览(43)
  • spring 的循环依赖以及spring为什么要用三级缓存解决循环依赖

            bean的生命周期         这里简单过一下 class -无参构造 -普通对象 -依赖注入(对加了autowire等的属性赋值) -初始化前-初始化 -初始化后(aop) -放入单例池的map(一级缓存) -bean对象 这里提一点单例bean单例bean 其实就是用mapbeanName,Bean对象创建的,多例bean就不

    2024年02月15日
    浏览(53)
  • Spring 为什么要用三级缓存来解决循环依赖(AOP),二级缓存不行吗

    解决有代理对象的循环依赖不一定要三级缓存,用二级甚至一级也能解决,下面讨论下Spring为什么选择三级缓存这个方案。 Spring最开始是没有三级缓存的,后面版本因为引入了AOP,有了代理对象,又因为存在循环依赖,为了保证依赖注入过程注入的是代理对象,且不完全打破

    2024年04月26日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包