当前位置: 首页 > 后端技术 > Java

三级缓存源码简析

时间:2023-04-01 16:58:41 Java

三级缓存用于解决Spring循环依赖问题。循环依赖出现在bean初始化链接中。Bean的初始化可以参考Bean源码分析。下面从源码的角度分析三级缓存。作用机制。1.源码位于org.springframework.beans.factory.support下的DefaultSingletonBeanRegistry//一级缓存,存放完全初始化的bean/**单例对象的缓存:bean名到bean实例。*/privatefinalMapsingletonObjects=newConcurrentHashMap<>(256);//二级缓存,存放半成品bean/**早期单例对象的缓存:bean名到bean实例。*/privatefinalMapearlySingletonObjects=newHashMap<>(16);//三级缓存,存放实例化的bean/**单例工厂的缓存:bean名到ObjectFactory。*/privatefinalMap>singletonFactories=newHashMap<>(16);假设一个场景,A依赖B,B依赖A。2.创建一个对象,从org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean开始/***返回指定bean的一个实例,可以是共享的也可以是独立的。*@paramname要检索的bean的名称*@paramrequiredType要检索的bean的必需类型*@paramargs使用显式参数创建bean实例时使用的参数*(仅在创建新实例时应用,而不是检索现有的)*@paramtypeCheckOnly实例是否为类型检查而获得,*不用于实际使用*@returnbean的实例*@throwsBeansException如果无法创建bean*/@SuppressWarnings("unchecked")protectedTdoGetBean(finalStringname,@NullablefinalClassrequiredType,@NullablefinalObject[]args,booleantypeCheckOnly)throwsBeansException{finalStringbeanName=transformedBeanName(姓名);对象豆;//急切地检查单例缓存以查找手动注册的单例。对象sharedInstance=getSingleton(beanName);if(sharedInstance!=null&&args==null){if(logger.isTraceEnabled()){if(isSingletonCurrentlyInCreation(beanName)){logger.trace("返回热切缓存的单例bean实例'"+beanName+"'那尚未完全初始化-循环引用的结果”);}else{logger.trace("返回单例bean的缓存实例'"+beanName+"'");bean=getObjectForBeanInstance(sharedInstance,name,beanName,null);其中,首先会检查缓存中是否有对象ObjectsharedInstance=getSingleton(beanName);,如果有就从缓存中取出,bean=getObjectForBeanInstance(sharedInstance,名称,beanName,空);3.然后看org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton方法/***返回在给定名称下注册的(原始)单例对象。*

检查已经实例化的单例并且还允许对当前创建的单例进行早期*引用(解决循环引用)。*@parambeanName要查找的bean的名称*@paramallowEarlyReference是否应该创建早期引用*@return已注册的单例对象,如果没有找到则返回{@codenull}*/@NullableprotectedObjectgetSingleton(StringbeanName,booleanallowEarlyReference){ObjectsingletonObject=this.singletonObjects.get(beanName);如果(singletonObject==null&&isSingletonCurrentlyInCreation(beanName)){同步(this.singletonObjects){singletonObject=this.earlySingletonObjects.get(beanName);如果(罪gletonObject==null&&allowEarlyReference){ObjectFactorysingletonFactory=this.singletonFactories.get(beanName);if(singletonFactory!=null){singletonObject=singletonFactory.getObject();this.earlySingletonObjects.put(beanName,singletonObject);this.singletonFactories.remove(beanName);}}}}返回单例对象;}代码很简单,依次查询三级缓存,缓存中存在则直接返回,尤其是在三级,如果拿到bean,只需在三级移除bean,添加第二层,应该到这里了。问题:二级缓存可以吗?这其实是一个设计问题。设计之初认为AOP代理是实例化完成后的行为,所以第三层是处理AOP,第二层是为了效率。如果存在多个循环依赖,直接从第二层获取增强对象,无需二次增强。