日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

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

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

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

第一類是構造方法中的循環依賴,這種會報錯

@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'); }} //錯誤提示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循環依賴,它分為兩種,第一類循環依賴的作用域scope默認是singleton,啟動不會報錯

@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是多例的,按理說這種啟動也會報錯,但是它成功了。。我也不知道為啥

@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'); }}

據我在網上查找的資料,spring可以幫我們處理bean的scope為singleton的field循環依賴,個人感覺應該也是這樣,下面說一下它的處理過程。

簡單說一下bean的加載過程,當spring啟動的時候,首先加載進beanFactory的是beanDefinition,之后會根據beanDefinition判斷其是否為sington并且為非抽象類非懶加載,那么之后會去創建bean,

bean的創建分為三步:

1.調用構造方法創建對象實例(這一步完成之后其它對象實例就可以引用它)

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

3.執行initializeBean方法,進行初始化

當bean進行創建時,會先調用getbean方法->執行doGetBean方法,在doGetBean方法中會調用getSingleton方法,這一步就是從三級緩存中獲取對象緩存,因為是剛開始創建bean所以緩存中肯定沒有,之后會調用createBean方法,在createBean方法中會調用doCreateBean執行bean的創建過程就是上面的那三步,當bean創建成功之后會將其放入一級緩存之中,此時會將它從三級和二級緩存中刪除。

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 { //從緩存中獲取實例 Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { //省略代碼 } else { //省略代碼 createBean(beanName, mbd, args); } //將創建完成的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 { //根據構造方法創建對象實例 BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { instanceWrapper = createBeanInstance(beanName, mbd, args); } final Object bean = instanceWrapper.getWrappedInstance(); //將對象實例放入第三級緩存中 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); //實例內部屬性填充 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; }

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

/** 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);

其實在getSingleton方法中會首先從一級緩存中獲取bean,一級緩存中沒有再從二級緩存中獲取,二級也沒有就會從三級中獲取factory當factory不為null時,則會調用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; }

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

而內部field scope為prototype為何也會報錯呢,當scope為prototype每次引用它時都會創建一個新的對象,所以也會存在循環創建的過程。

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

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

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

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

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

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持好吧啦網。如有錯誤或未考慮完全的地方,望不吝賜教。

標簽: Spring
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
欧美成人日韩| 91欧美在线| 亚洲女同一区| 私拍精品福利视频在线一区| 日韩欧美午夜| 色爱综合av| 99精品视频精品精品视频| 日韩中文字幕高清在线观看| 日韩高清成人| 亚洲精品一二三区区别| 欧美 日韩 国产精品免费观看| 欧美日韩国产一区二区三区不卡 | 国产理论在线| 国产成人精品一区二区三区免费| 国产成人精品亚洲线观看| 激情久久久久久| 91精品一区二区三区综合| 亚洲综合婷婷| 欧美日韩一区二区国产| 国产一区二区三区亚洲综合| 欧美精选视频一区二区| 亚洲欧洲日本mm| 无码日韩精品一区二区免费| 欧美欧美黄在线二区| 国产精品红桃| 日本久久精品| 婷婷综合在线| 日韩黄色免费网站| 欧美日本不卡| 国产不卡人人| 美女久久一区| 国产精品4hu.www| 久久精品卡一| 亚洲免费专区| 国模大尺度视频一区二区| 蜜桃视频欧美| 欧美日韩一区二区国产 | 久久精品国产大片免费观看| 免费视频一区二区| 91p九色成人| 福利在线免费视频| av一区二区高清| 人人爱人人干婷婷丁香亚洲| 黄在线观看免费网站ktv| 在线视频亚洲| 嫩草伊人久久精品少妇av杨幂| 91tv亚洲精品香蕉国产一区| 亚洲专区视频| 神马久久午夜| 日韩影片在线观看| 中文字幕系列一区| 国产午夜精品一区在线观看| 久久婷婷一区| 91精品麻豆| japanese国产精品| 国产精久久久| av一区二区高清| 欧美精品第一区| 欧美91精品| 国产精品s色| 亚洲综合精品| 中文字幕人成乱码在线观看| 蜜臀精品一区二区三区在线观看| 精品视频在线观看网站| 欧美日韩国产一区精品一区| 美女尤物国产一区| 视频一区视频二区在线观看| 国产在线视频欧美一区| 中文字幕一区二区av| 欧美日韩国产v| 国产欧美一级| 99国产精品视频免费观看一公开| 久久中文字幕一区二区三区| 在线精品一区| 久久中文字幕av| 精品午夜av| 欧美精品观看| 婷婷成人av| 欧美在线综合| 在线日韩欧美| 国产va在线视频| 国产精品22p| 日韩av网站在线观看| 国产视频欧美| 日韩美女一区二区三区在线观看| 国产剧情在线观看一区| 日韩精品一卡二卡三卡四卡无卡| 福利片在线一区二区| 91精品福利观看| 亚洲3区在线| 免费日韩av| 欧美午夜不卡| 婷婷激情久久| 日韩中文影院| 国产第一亚洲| 蜜桃久久久久| 国产精品亚洲产品| 久久xxxx精品视频| 亚洲福利免费| 美女一区网站| 国产精品久久久久蜜臀 | 精品一级视频| 麻豆一区二区在线| 欧美日韩精品一区二区三区在线观看| 亚洲欧美日韩综合国产aⅴ| 久久精品影视| 91精品国产成人观看| 成人欧美一区二区三区的电影| 麻豆久久一区二区| 国产精品1区在线| 国产精品亲子伦av一区二区三区| 日韩国产一二三区| 亚洲精品自拍| 日韩在线视频一区二区三区| 亚洲一二av| 中文字幕一区二区av| 中文字幕乱码亚洲无线精品一区| 蜜臀精品一区二区三区在线观看| 久久亚洲国产精品一区二区| 老司机精品久久| 美美哒免费高清在线观看视频一区二区| 国产亚洲在线| 免费人成精品欧美精品| 在线精品亚洲| 日本午夜精品久久久| 国产一卡不卡| 国产精品成人一区二区网站软件| 国产欧美久久一区二区三区| 欧美一级二区| 国产精品1区| 久久精品人人| 久久毛片亚洲| 99久久亚洲精品蜜臀| 图片区亚洲欧美小说区| 久久最新视频| 日韩成人精品一区二区三区| 欧美日本久久| 国产一区二区三区亚洲综合| 欧美日韩视频免费观看| 欧美国产91| 一区二区三区网站| 欧美一级网址| 日韩av自拍| 欧美日韩激情| 日韩1区2区3区| 国产探花在线精品一区二区| 欧美aⅴ一区二区三区视频| 精精国产xxxx视频在线野外| 99精品99| 亚洲午夜黄色| 在线精品小视频| 久久精品亚洲一区二区| 欧美精品一区二区三区精品| 亚洲开心激情| 日韩精品久久久久久| 日韩一区免费| 在线一区免费观看| 国产一区2区| 久久国产麻豆精品| 国产精品美女在线观看直播| 久久中文字幕一区二区三区| 久久久久伊人| 久久婷婷亚洲| 日韩精品一二三四| 国产欧美日韩一级| 欧美成人基地 | 美女黄网久久| 国产亚洲电影| 久久精品一区二区不卡| 午夜久久av| 久久不见久久见免费视频7| 日本国产精品| 亚洲精品美女91| 国产自产自拍视频在线观看| 久久国产88| 老司机免费视频一区二区三区| 亚洲高清成人| 国产精品免费大片| 九一国产精品| 国产精品成人一区二区网站软件| 99久久久久| 88久久精品| 91九色精品| 欧美激情三区| 亚洲激情精品| 国产一级成人av| 国产精品88久久久久久| 卡一卡二国产精品| 综合激情网站| 日韩一区电影| 欧美日韩网址| 九九综合九九| 久久久久伊人| 美国欧美日韩国产在线播放| 成人黄色av| 91九色综合| 亚洲免费黄色| 91一区二区| 青青伊人久久| 亚洲免费婷婷|