论 spring 的三级缓存

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

论 spring 的三级缓存

预备知识

bean的生命周期

论 spring 的三级缓存

bean 的生命周期

为何会出现循环引用

这个问题只是出现在spring 容器的机制中,其实我们代码中很简单就解决了。

假设A 对象里需要注入一个B属性,B 对象里面需要注入一个A 属性。根据Bean 的生命周期,先实例化A 的实例,然后进行A属性的填充,这时就需要一个B的对象,在通过 beanFactory.getBean(B) 进行B对象的获取,同样,先进行B的实例化,之后进行B中A属性的复制,也会去调用beanFactory.getBean(A),进行获取,但是A变量还没有创建完成,singletonObjects变量池中没有,所以就行程了循环引用,为了解决这个问题就是A实例化之后,想找一个变量进行存储,后面有变量的创建需要用到她的话,直接使用这个变量的对象,earlySingletonObjects ,这样就解决了循环依赖的问题。

伪代码如下:

//伪代码就是这个意思 
static class A {
        private B b;

        public void setB(B b) {
            this.b = b;
        }
    }
    static class B {
        private A a;

        public void setA(A a) {
            this.a = a;
        }
    }

    public static void main(String[] args) {
        A earlySingletonObjects = new A();
        B b;
        {
            b = new B();
            b.setA(earlySingletonObjects);
        }
        earlySingletonObjects.setB(b);
        A a = earlySingletonObjects;
        // TODO:  use a use b 
    }

不用三级缓存行不行

首先提出一个观点,不用三级缓存,使用两级缓存行不行,答案是肯定的,没问题,spring 为什么要使用三个变量池呢,我想是这样分类更明确。

说道分类明确,大家不禁有疑问,为什么这么说呢,是因为 假设 A 和B 之间进行循环引用,并且我们对A 进行了切面增强逻辑,如果我们只是将A的实例对象提前暴露出去是错误的,因为B中我们真正想使用的是A增强后的对象。好了,问题说清楚了,那用两个变量行不行,当然行了,创建A 的时候我们在进行属性赋值的时候,直接创建一个包含A 的代理对象,并将代理对象放入earlySingletonObjects 提前暴露变量池中,不就ok了吗,等到B使用的时候直接拿到A的代理对象,没有任何问题。所以我个人认为spring 在弄出一个singletonFactories 单纯就是解耦。

三级缓存,不 ,是三个变量

分别存储在 这三个变量当中.

private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

三个对象的赋值过程

过程详解

代码如下:

  1. org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {	
    if (earlySingletonExposure) {
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }
}
  1. org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
		Object sharedInstance = getSingleton(beanName);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}
  1. org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory<?>)
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    synchronized (this.singletonObjects) {
        singletonObject = singletonFactory.getObject();
        newSingleton = true;
        if (newSingleton) {
            //该方法
            addSingleton(beanName, singletonObject);
        }
        return singletonObject;
     }
}

protected void addSingleton(String beanName, Object singletonObject) {
    synchronized (this.singletonObjects) {
        this.singletonObjects.put(beanName, singletonObject);
        this.singletonFactories.remove(beanName);
        this.earlySingletonObjects.remove(beanName);
        this.registeredSingletons.add(beanName);
    }
}

扩展出aop 代理对象如何创建

首先我们开启aspectj的注解会给容器注册一个 BeanPostProcessor class name 为 AnnotationAwareAspectJAutoProxyCreator

@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
}
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
			BeanDefinitionRegistry registry, @Nullable Object source) {

		return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
	}

AnnotationAwareAspectJAutoProxyCreator 的继承结构如下:

那么在什么时机去创建代理呢? 有两个时机,第一个是允许提前暴露的话,在实例化好目标对象之后,提前暴露给singletonFactories 当中时,使用getEarlyBeanReference 方法进行动态代理的替换

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {
    	BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);
		
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
            //使用getEarlyBeanReference 方法进行动态代理的替换
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}
		Object exposedObject = bean;
		try {
			populateBean(beanName, mbd, instanceWrapper);
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		return exposedObject;
	}

getEarlyBeanReference 所做的内容,会调用所有的SmartInstantiationAwareBeanPostProcessor 的getEarlyBeanReference 方法

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
		Object exposedObject = bean;
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
					SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
					exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
				}
			}
		}
		return exposedObject;
	}

此时创建代理对象

public Object getEarlyBeanReference(Object bean, String beanName) {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		this.earlyProxyReferences.put(cacheKey, bean);
		return wrapIfNecessary(bean, beanName, cacheKey);
	}

剩下得流程该对目标对象属性赋值就赋值,该初始化初始化。一切照旧,只不过我们提前暴露的是 代理对象.

而after 做的是将为提前暴露的对象在代理一次

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}

关于spring aop的源码分析,可以参看:

<<spring技术内幕>>文章来源地址https://www.toymoban.com/news/detail-447706.html

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

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

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

相关文章

  • 【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的三级缓存原理

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

    2024年02月04日
    浏览(38)
  • 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使用三级缓存解决循环依赖?终于完全弄明白了

    文章阅读前推荐 推荐先去看看源码,源码很短,但是对于我们在脑子里构建一个完整思路很重要。看起来非常简单,只需要双击shift,全局查找文件:AbstractAutowireCapableBeanFactory,找到550行左右的doCreateBean方法,重点看一下580行到600行这20行代码就行,包含了三级缓存、属性注

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

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

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

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

    2024年02月15日
    浏览(53)
  • Spring FrameWork从入门到NB -三级缓存解决循环依赖内幕 (一)

    循环依赖就是我依赖你、你依赖我,或者A依赖B、B依赖C、C依赖A…组成的错综复杂的依赖关系。 其实各种不同的依赖关系最终从逻辑上都可以演变为:我依赖你、你依赖我。 循环依赖大致可以分为两种情况: 属性依赖:比如A对象有一个属性B,B对象有属性A。 构造器依赖:

    2024年02月11日
    浏览(47)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包