电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術(shù)文章
文章詳情頁

SpringBean依賴和三級緩存的案例講解

瀏覽:7日期:2023-07-21 15:44:53

spring中的bean依賴有大體上可以分為兩類,共3中形式,下面簡單介紹一下。

第一類是構(gòu)造方法中的循環(huán)依賴,這種會報(bào)錯(cuò)

@Servicepublic class ServiceA { private ServiceB serviceB; public ServiceA(ServiceB serviceB) { this.serviceB = serviceB; } public void methodA(){ System.out.println('a'); }} @Servicepublic class ServiceB { private ServiceA serviceA; public ServiceB(ServiceA serviceA) { this.serviceA = serviceA; } public void methodB(){ System.out.println('b'); }} //錯(cuò)誤提示Description: The dependencies of some of the beans in the application context form a cycle: ┌─────┐| serviceA defined in file [C:demotargetclassescomexampledemoServiceA.class]↑ ↓| serviceB defined in file [C:demotargetclassescomexampledemoServiceB.class]└─────┘

第二類是field循環(huán)依賴,它分為兩種,第一類循環(huán)依賴的作用域scope默認(rèn)是singleton,啟動(dòng)不會報(bào)錯(cuò)

@Servicepublic class ServiceA { @Autowired private ServiceB serviceB; public void methodA(){ System.out.println('a'); }} @Servicepublic class ServiceB { @Autowired private ServiceA serviceA; public void methodB(){ System.out.println('b'); }}

第二種作用域scope為prototype,在這種情況下bean是多例的,按理說這種啟動(dòng)也會報(bào)錯(cuò),但是它成功了。。我也不知道為啥

@Service@Scope('prototype')public class ServiceA { @Autowired private ServiceB serviceB; public void methodA(){ System.out.println('a'); }} @Service@Scope('prototype')public class ServiceB { @Autowired private ServiceA serviceA; public void methodB(){ System.out.println('b'); }}

據(jù)我在網(wǎng)上查找的資料,spring可以幫我們處理bean的scope為singleton的field循環(huán)依賴,個(gè)人感覺應(yīng)該也是這樣,下面說一下它的處理過程。

簡單說一下bean的加載過程,當(dāng)spring啟動(dòng)的時(shí)候,首先加載進(jìn)beanFactory的是beanDefinition,之后會根據(jù)beanDefinition判斷其是否為sington并且為非抽象類非懶加載,那么之后會去創(chuàng)建bean,

bean的創(chuàng)建分為三步:

1.調(diào)用構(gòu)造方法創(chuàng)建對象實(shí)例(這一步完成之后其它對象實(shí)例就可以引用它)

2.填充實(shí)例內(nèi)部屬性(會依次從三級緩存中獲取依賴的bean,如果沒有找到,則會先去創(chuàng)建依賴的bean,之后再返回繼續(xù)填充屬性)

3.執(zhí)行initializeBean方法,進(jìn)行初始化

當(dāng)bean進(jìn)行創(chuàng)建時(shí),會先調(diào)用getbean方法->執(zhí)行doGetBean方法,在doGetBean方法中會調(diào)用getSingleton方法,這一步就是從三級緩存中獲取對象緩存,因?yàn)槭莿傞_始創(chuàng)建bean所以緩存中肯定沒有,之后會調(diào)用createBean方法,在createBean方法中會調(diào)用doCreateBean執(zhí)行bean的創(chuàng)建過程就是上面的那三步,當(dāng)bean創(chuàng)建成功之后會將其放入一級緩存之中,此時(shí)會將它從三級和二級緩存中刪除。

public Object getBean(String name) throws BeansException { return doGetBean(name, null, null, false); } doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { //從緩存中獲取實(shí)例 Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { //省略代碼 } else { //省略代碼 createBean(beanName, mbd, args); } //將創(chuàng)建完成的bean放入一級緩存 addSingleton(beanname,object) } protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { //省略代碼 doCreateBean() } protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException { //根據(jù)構(gòu)造方法創(chuàng)建對象實(shí)例 BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { instanceWrapper = createBeanInstance(beanName, mbd, args); } final Object bean = instanceWrapper.getWrappedInstance(); //將對象實(shí)例放入第三級緩存中 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); //實(shí)例內(nèi)部屬性填充 populateBean(beanName, mbd, instanceWrapper); //初始化bean exposedObject = initializeBean(beanName, exposedObject, mbd); return exposedObject; } 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; }

其中我們可以看到當(dāng)?shù)谝徊綀?zhí)行完畢后會將剛剛創(chuàng)建的實(shí)例放入singletonFactories(第三級緩存)中,那么我們下面了解下到底什么是spring的三級緩存。處于最上層的緩存是singletonObjects,它其中存儲的對象是完成創(chuàng)建好,可以正常使用的bean,二級緩存叫做earlySingletonObjects,它其中存儲的bean是僅執(zhí)行了第一步通過構(gòu)造方法實(shí)例化,并沒有填充屬性和初始化,第三級緩存singletonFactories是一個(gè)工場。

/** Cache of singleton objects: bean name to bean instance. */ 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);

其實(shí)在getSingleton方法中會首先從一級緩存中獲取bean,一級緩存中沒有再從二級緩存中獲取,二級也沒有就會從三級中獲取factory當(dāng)factory不為null時(shí),則會調(diào)用getObject方法獲取bean,并將bean放入二級緩存,之后再從三級緩存中刪除該key-value對,代碼如下:

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; }

那么到此處我們就可以看出為什么不能在構(gòu)造方法中存在循環(huán)依賴了,假如現(xiàn)在有a、b兩個(gè)service,它們兩個(gè)互相在構(gòu)造方法中循環(huán)依賴,當(dāng)項(xiàng)目啟動(dòng),創(chuàng)建a的bean時(shí)執(zhí)行第一步通過構(gòu)造方法創(chuàng)建實(shí)例,但是發(fā)現(xiàn)依賴b的bean,所以就從三級緩存中獲取,但是沒發(fā)現(xiàn),那么就先掛起a的創(chuàng)建過程,先去創(chuàng)建b,在b創(chuàng)建過程中,又依賴于a,但是三級緩存中也沒有a的bean,這樣就進(jìn)入了一個(gè)循環(huán)創(chuàng)建的過程,自然是不可取的。

而內(nèi)部field scope為prototype為何也會報(bào)錯(cuò)呢,當(dāng)scope為prototype每次引用它時(shí)都會創(chuàng)建一個(gè)新的對象,所以也會存在循環(huán)創(chuàng)建的過程。

而默認(rèn)情況下bean的scope為singleton,整個(gè)容器中僅有整個(gè)service的一個(gè)bean,還是假如a、b兩service存在field循環(huán)依賴,當(dāng)創(chuàng)建a的bean時(shí),執(zhí)行完構(gòu)造方法后,a的實(shí)例已生成,將其factory對象存入第三級緩存singletonFactories中,在填充屬性時(shí),發(fā)現(xiàn)依賴b的bean,但是在緩存中沒有b的bean;因此轉(zhuǎn)而去創(chuàng)建b,在此過程中執(zhí)行完b的構(gòu)造方法后將其factory也放入三級緩存,此時(shí)執(zhí)行b的屬性填充,發(fā)現(xiàn)依賴a,從三級緩存中獲取a的對象,并將a放入二級緩存中,之后執(zhí)行intialize初始化,最后將b的bean轉(zhuǎn)入一級緩存;再繼續(xù)回來創(chuàng)建a,這個(gè)時(shí)候發(fā)現(xiàn)在一級緩存中已經(jīng)有了b,那么屬性填充成功,進(jìn)行初始化,最后a也放入一級緩存,至此執(zhí)行完畢。

那么大家可能會感到疑惑,為什么要使用三級緩存呢,感覺沒有singletonFactories使用二級緩存也可以呀?

從前面的代碼里可以看到向第三級緩存中放置的是一個(gè)objectFactory的匿名實(shí)現(xiàn)類,addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)),當(dāng)我們從singletonFactories中獲取objectFctory然后調(diào)用getObject方法獲取bean的時(shí)候,實(shí)際就是通過getEarlyBeanReference獲取的object,那么進(jìn)入這個(gè)方法看一下。

它在這里會獲取所有的beanPostProcessor實(shí)現(xiàn)類,然后從中找出實(shí)現(xiàn)了SmartInstantiationAwareBeanPostProcessor的beanPostProcessor,然后調(diào)用它的getEarlyBeanReference(obgect,beanName)方法,對bean進(jìn)行處理,然后進(jìn)行返回,這些實(shí)現(xiàn)類中就有aop的核心AbstractAutoProxyCreator,從這里我們就可以看出來,從第三級緩存objectFactory中獲取的obejct是經(jīng)過了處理的一個(gè)代理對象,個(gè)人理解三級緩存就是為了獲取在創(chuàng)建對象的過程中提前對其進(jìn)行一些擴(kuò)展操作。

三級緩存實(shí)現(xiàn)bean的擴(kuò)展,將代理對象放入二級緩存中,供其他依賴該bean的對象的使用,如果沒有了三級緩存,將bean擴(kuò)展放在二級緩存中實(shí)現(xiàn),那么如果有bean a被其他多個(gè)bean依賴,那么在其他bean填充屬性的過程中會多次獲取bean a,這個(gè)過程中就會多次執(zhí)行獲取bean a代理,就有些多余,而三級緩存結(jié)構(gòu)就是在第三級緩存完成bean的擴(kuò)展,生成代理對象,放入二級緩存之中,供其他bean獲取。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持好吧啦網(wǎng)。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。

標(biāo)簽: Spring
相關(guān)文章:
主站蜘蛛池模板: 扬尘在线监测系统_工地噪声扬尘检测仪_扬尘监测系统_贝塔射线扬尘监测设备「风途物联网科技」 | NMRV减速机|铝合金减速机|蜗轮蜗杆减速机|NMRV减速机厂家-东莞市台机减速机有限公司 | 山东限矩型液力偶合器_液力耦合器易熔塞厂家-淄博市汇川源机械厂 | 月嫂_保姆_育婴_催乳_母婴护理_产后康复_养老护理-吉祥到家家政 硫酸亚铁-聚合硫酸铁-除氟除磷剂-复合碳源-污水处理药剂厂家—长隆科技 | 衢州装饰公司|装潢公司|办公楼装修|排屋装修|别墅装修-衢州佳盛装饰 | 分光色差仪,测色仪,反透射灯箱,爱色丽分光光度仪,美能达色差仪维修_苏州欣美和仪器有限公司 | 钢托盘,铁托盘,钢制托盘,镀锌托盘,饲料托盘,钢托盘制造商-南京飞天金属13260753852 | 恒温槽_恒温水槽_恒温水浴槽-上海方瑞仪器有限公司 | 宝元数控系统|对刀仪厂家|东莞机器人控制系统|东莞安川伺服-【鑫天驰智能科技】 | 流量卡中心-流量卡套餐查询系统_移动电信联通流量卡套餐大全 | 高铝轻质保温砖_刚玉莫来石砖厂家_轻质耐火砖价格 | 折弯机-刨槽机-数控折弯机-数控刨槽机-数控折弯机厂家-深圳豐科机械有限公司 | 真空泵维修保养,普发,阿尔卡特,荏原,卡西亚玛,莱宝,爱德华干式螺杆真空泵维修-东莞比其尔真空机电设备有限公司 | 酵素生产厂家_酵素OEM_酵素加盟_酵素ODM_酵素原料厂家_厦门益力康 | Honsberg流量计-Greisinger真空表-气压计-上海欧臻机电设备有限公司 | 广东佛电电器有限公司|防雷开关|故障电弧断路器|智能量测断路器 广东西屋电气有限公司-广东西屋电气有限公司 | 今日热点_实时热点_奇闻异事_趣闻趣事_灵异事件 - 奇闻事件 | MES系统工业智能终端_生产管理看板/安灯/ESOP/静电监控_讯鹏科技 | 福建自考_福建自学考试网| 多功能三相相位伏安表-变压器短路阻抗测试仪-上海妙定电气 | 紧急切断阀_气动切断阀_不锈钢阀门_截止阀_球阀_蝶阀_闸阀-上海上兆阀门制造有限公司 | 药品仓库用除湿机-变电站用防爆空调-油漆房用防爆空调-杭州特奥环保科技有限公司 | 熔体泵|换网器|熔体齿轮泵|熔体计量泵厂家-郑州巴特熔体泵有限公司 | 防爆正压柜厂家_防爆配电箱_防爆控制箱_防爆空调_-盛通防爆 | 东莞市踏板石餐饮管理有限公司_正宗桂林米粉_正宗桂林米粉加盟_桂林米粉加盟费-东莞市棒子桂林米粉 | 智能终端_RTU_dcm_北斗星空自动化科技 | 硫化罐_蒸汽硫化罐_大型硫化罐-山东鑫泰鑫智能装备有限公司 | 江苏全风,高压风机,全风环保风机,全风环形高压风机,防爆高压风机厂家-江苏全风环保科技有限公司(官网) | 派克防爆伺服电机品牌|国产防爆伺服电机|高低温伺服电机|杭州摩森机电科技有限公司 | 密封圈_泛塞封_格莱圈-[东莞市国昊密封圈科技有限公司]专注密封圈定制生产厂家 | 变色龙云 - 打包app_原生app_在线制作平台_短链接_ip查询 | 防水套管_柔性防水套管_刚性防水套管-巩义市润达管道设备制造有限公司 | KBX-220倾斜开关|KBW-220P/L跑偏开关|拉绳开关|DHJY-I隔爆打滑开关|溜槽堵塞开关|欠速开关|声光报警器-山东卓信有限公司 | 自动售货机_无人售货机_专业的自动售货机运营商_免费投放售货机-广州富宏主官网 | 非标压力容器_碳钢储罐_不锈钢_搪玻璃反应釜厂家-山东首丰智能环保装备有限公司 | 电地暖-电采暖-发热膜-石墨烯电热膜品牌加盟-暖季地暖厂家 | 台湾阳明固态继电器-奥托尼克斯光电传感器-接近开关-温控器-光纤传感器-编码器一级代理商江苏用之宜电气 | 动物解剖台-成蚊接触筒-标本工具箱-负压实验台-北京哲成科技有限公司 | 上海公司注册-代理记账-招投标审计-上海昆仑扇财税咨询有限公司 上海冠顶工业设备有限公司-隧道炉,烘箱,UV固化机,涂装设备,高温炉,工业机器人生产厂家 | 气力输送_输送机械_自动化配料系统_负压吸送_制造主力军江苏高达智能装备有限公司! | 订做不锈钢_不锈钢定做加工厂_不锈钢非标定制-重庆侨峰金属加工厂 |