• spring三级缓存


    目录

    文章目录

    前言

    一、spring三级缓存是什么?

    二、分析步骤

    总结


    前言

    spring三级缓存用来解决spring的循环依赖问题

    目前循环依赖只在属性set注入且单例的情况下才能解决

    构造器注入和多例的循环依赖情况下是无法解决的


    提示:以下是本篇文章正文内容,下面案例可供参考

    一、spring三级缓存是什么?

    singletonObjects > 一级缓存
    singletonFactories > 三级缓存
    earlySingletonObjects > 二级缓存

    二、分析步骤

    1.循环依赖示例:

    @Service
    public class AService {
    
        private BService bService;
    
        public AService() {
    
            System.out.println("Aservice 构造方法执行---------");
        }
    
        public BService getbService() {
            return bService;
        }
    
        public void setbService(BService bService) {
            this.bService = bService;
        }
    }
    
    
    
    
    @Service
    public class BService {
    
        private AService aService;
    
    
        public BService() {
            System.out.println("bService 构造方法--------");
        }
    
        public AService getaService() {
            return aService;
        }
    
        public void setaService(AService aService) {
            this.aService = aService;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    当容器初始化加载两个bean时,会造成A,B相互依赖,查看bean生命周期,可以追踪循环依赖的解决方式

    首先容器会通过doGetBean()获取AService,

    /**
    	 * Return the (raw) singleton object registered under the given name.
    	 * 

    Checks already instantiated singletons and also allows for an early * reference to a currently created singleton (resolving a circular reference). * @param beanName the name of the bean to look for * @param allowEarlyReference whether early references should be created or not * @return the registered singleton object, or {@code null} if none found */ @Nullable 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; } // 如果获取不到,则创建 if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { try { //创建 return createBean(beanName, mbd, args); } catch (BeansException ex) { destroySingleton(beanName); throw ex; } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    通过doCreateBean()方法创建Aservice

    // Eagerly cache singletons to be able to resolve circular references
    		// even when triggered by lifecycle interfaces like BeanFactoryAware.
    		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
    				isSingletonCurrentlyInCreation(beanName));
    		if (earlySingletonExposure) {
    			if (logger.isTraceEnabled()) {
    				logger.trace("Eagerly caching bean '" + beanName +
    						"' to allow for resolving potential circular references");
    			}
    			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    		}
    
    
    
    
    //放入三级缓存后,准备初始化bean实例,接着填充属性操作
    // Initialize the bean instance.
    		Object exposedObject = bean;
    		try {
    			populateBean(beanName, mbd, instanceWrapper);
    			exposedObject = initializeBean(beanName, exposedObject, mbd);
    		}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    会先把AService放入三级缓存,

    key: beanName value值 :() -> getEarlyBeanReference(beanName, mbd, bean)

    具体的addSingletonFactory() 方法

    protected void addSingletonFactory(String beanName, ObjectFactory singletonFactory) {
    		Assert.notNull(singletonFactory, "Singleton factory must not be null");
    		synchronized (this.singletonObjects) {
    			if (!this.singletonObjects.containsKey(beanName)) {
    				this.singletonFactories.put(beanName, singletonFactory);
    				this.earlySingletonObjects.remove(beanName);
    				this.registeredSingletons.add(beanName);
    			}
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    AService填充属性,需要注入BService

    解析依赖方法:

    private Object resolveReference(Object argName, RuntimeBeanReference ref) {
    		try {
    			Object bean;
    			String refName = ref.getBeanName();
    			refName = String.valueOf(doEvaluate(refName));
    			if (ref.isToParent()) {
    				if (this.beanFactory.getParentBeanFactory() == null) {
    					throw new BeanCreationException(
    							this.beanDefinition.getResourceDescription(), this.beanName,
    							"Can't resolve reference to bean '" + refName +
    							"' in parent factory: no parent factory available");
    				}
    				bean = this.beanFactory.getParentBeanFactory().getBean(refName);
    			}
    			else {
                    //此处回去获取BService bean实例
    				bean = this.beanFactory.getBean(refName);
    				this.beanFactory.registerDependentBean(refName, this.beanName);
    			}
    			if (bean instanceof NullBean) {
    				bean = null;
    			}
    			return bean;
    		}
    		catch (BeansException ex) {
    			throw new BeanCreationException(
    					this.beanDefinition.getResourceDescription(), this.beanName,
    					"Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    而容器中还没有Bservice的Bean,及需要先创建BService的bean

    BService的创建也是先经过上述步骤

    先把BService的未成品的bean放入三级缓存

    然后BService的bean 填充属性 AService

    这时getSingleton()方法如下

    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);
    					//从一级缓存未找到AService的Bean且allowEarlyReference为true,
                        //就把AService的Bean放到二级缓存中
                        if (singletonFactory != null) {
    						singletonObject = singletonFactory.getObject();
    						this.earlySingletonObjects.put(beanName, singletonObject);
    						this.singletonFactories.remove(beanName);
    					}
    				}
    			}
    		}
    		return singletonObject;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    之后BService的Bean属性填充完毕,创建实例Bean完成,让后将Bean放入的一级缓存

    /**
    	 * Add the given singleton object to the singleton cache of this factory.
    	 * 

    To be called for eager registration of singletons. * @param beanName the name of the bean * @param singletonObject the singleton object */ 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); } }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    接下来回到Aservice的Bean的 填充属性方法

    获取到Bservice的Bean实例,

    属性填充完毕

    会直接把AService的Bean实例放到一级缓存中,

    至此实例化ABService完成


    总结

    循环依赖似乎只要二级缓存就能解决,为何还要三级缓存,

    个人理解:其实在最开始放入三级缓存的value,lambda表达式,即用来解决AOP代理的bean相互依赖的的问题,如果需要代理,则提前暴露代理对象放入的其他缓存,否则提前生成普通代理对象实例放入其他缓存即可

    先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦

  • 相关阅读:
    SpringCloud Gateway 网关的请求体body的读取和修改
    Linux下“多线程”相关内容整理总结
    2023下半年软考各地区准考证打印时间汇总
    内网Jenkins 部署.net(dotnet)项目
    python之Scipy
    常见关系型数据库SQL增删改查语句
    vivado里那些看不懂的原语
    使用adb命令打开应用
    第五章 延迟计算
    对比两个数组中 每个对应位置的元素大小 返回每个对比结果组成的列表 numpy.fmin()
  • 原文地址:https://blog.csdn.net/m0_66557301/article/details/126079910