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

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

springboot bean循環依賴實現以及源碼分析

瀏覽:133日期:2023-03-01 10:56:47
目錄前言1、什么叫循環依賴呢2、具體出現循環依賴的代碼邏輯3、解決循環依賴的代碼實現總結前言

本文基于springboot版本2.5.1

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.1</version><relativePath/> <!-- lookup parent from repository --> </parent>

本文主要聚焦在循環依賴部分,主要用單例bean來進行講解,其他bean實現的流程不會過多涉及。

1、什么叫循環依賴呢

簡單來說就是springboot容器中的多個bean,如A、B兩個bean,A有屬性B需要注入,B有屬性A需要注入,形成相互依賴的情況。

看下代碼,就是類似下面這種情況

import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;@Componentpublic class ServiceA { @Autowired private ServiceB serviceB;}

import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;@Componentpublic class ServiceB { @Autowired private ServiceA serviceA;}

上面有兩個bean,分別是ServiceA,ServiceB。ServiceA中需要注入ServiceB的實例,ServiceB中需要注入ServiceA的實例,這就是一種典型的循環依賴,其他還有方法參數循環依賴的場景等等,但是它們的內部實現基本是一樣的。

2、具體出現循環依賴的代碼邏輯

獲取bean的方法

在springboot中默認的beanFactory是DefaultListableBeanFactory,在我們獲取bean對象的時候,如果bean對象存在就直接返回,如果不存在,就先創建bean對象再返回。

我們先看下我們獲取bean的常用方法都有哪些

public <T> T getBean(Class<T> requiredType) throws BeansExceptionpublic Object getBean(String name) throws BeansExceptionpublic <T> Map<String, T> getBeansOfType(@Nullable Class<T> type) throws BeansExceptionpublic Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType)public void preInstantiateSingletons() throws BeansException

常用的獲取bean的方法主要有上面幾個和它們的重載版本,對于第3行、第4行、第5行最終都會調用到第2行的方法來獲取bean。而它也會通過調用doGetBean(在AbstractBeanFactory這個類中)來獲取bean

public Object getBean(String name) throws BeansException { return doGetBean(name, null, null, false); }

第1行的方法也會調用doGetBean來獲取bean

public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args) throws BeansException { return doGetBean(name, requiredType, args, false); }

所有最終獲取bean的方法都是

protected <T> T doGetBean( String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {

這個方法,這個方法是protected的,是不對外提供的。所以我們不能直接調用它,只能通過上面提供的5個方法來獲取bean對象。

下面我們從doGetBean這里來看下serviceA創建的過程

protected <T> T doGetBean( String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException { //如果bean之前存在,這里返回的shareInstance就是非空,就會從后面的if分支中返回,如果bean之前不存在,就會執行后面的bean創建及注入屬性的過程 Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { ...... //如果當前不只是檢查,而且是創建bean,這個參數就是false,在這里就會做個bean創建的標記,把beanName 加到alreadyCreated里面去 if (!typeCheckOnly) { markBeanAsCreated(beanName); } //我們當前要創建的bean是單例的,就會走到這里去,下面我們走到里面的調用去看看 // Create bean instance. if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { // Explicitly remove instance from singleton cache: It might have been put there // eagerly by the creation process, to allow for circular reference resolution. // Also remove any beans that received a temporary reference to the bean. destroySingleton(beanName); throw ex; } }); beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } }

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(beanName, 'Bean name must not be null'); synchronized (this.singletonObjects) {......//這里會把當前bean的名字加入到當前正在創建的單例對象集合singletonsCurrentlyInCreation中 beforeSingletonCreation(beanName); ...... try { //這里就是調用上面的return createBean(beanName, mbd, args);這個方法,我們進這里面去看看 singletonObject = singletonFactory.getObject(); newSingleton = true; } ...... } return singletonObject; } }

@Override protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { ...... // Make sure bean class is actually resolved at this point, and // clone the bean definition in case of a dynamically resolved Class // which cannot be stored in the shared merged bean definition.//在這里獲取要創建的bean的class對象 Class<?> resolvedClass = resolveBeanClass(mbd, beanName); ...... try { //調用這里來創建,我們再走到這里面去看看 //3個參數分別為 //1、beanName bean對象的名字 //2、mbdToUseRootBeanDefinition對象,可以認為就是bean的元數據信息,包含bean的類對象,bean的類上注解,bean實際位置路徑等等 //3、args bean對象的構造方法的實參,這里一般是空的 Object beanInstance = doCreateBean(beanName, mbdToUse, args); if (logger.isTraceEnabled()) { logger.trace('Finished creating instance of bean ’' + beanName + '’'); } return beanInstance; } ...... }

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { ...... //真正創建bean對象是在這里,這里返回的instanceWrapper是bean對象的類實例的包裝對象BeanWrapper if (instanceWrapper == null) { instanceWrapper = createBeanInstance(beanName, mbd, args); } //這里的bean就是實際創建的bean對象的類實例 Object bean = instanceWrapper.getWrappedInstance(); Class<?> beanType = instanceWrapper.getWrappedClass(); if (beanType != NullBean.class) { mbd.resolvedTargetType = beanType; } ...... // Eagerly cache singletons to be able to resolve circular references // even when triggered by lifecycle interfaces like BeanFactoryAware. //看上面的注釋大概也能明白, 大概意思就是早期的單例緩存,為了解決由 BeanFactoryAware等等觸發的循環依賴 //mbd.isSingleton() 表示bean是單例的(這個是bean對應的類上的,默認就是單例), //this.allowCircularReferences 允許循環引用,這個是beanFactory的成員屬性,默認也是true //isSingletonCurrentlyInCreation(beanName) 表示是否在當前正在創建的bean集合中。beforeSingletonCreation(beanName);我們在前面執行過這句就加到正在創建的bean集合中了 //這里earlySingletonExposure 就是true了,會進到if分支中 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'); } //這句主要是將將() -> getEarlyBeanReference(beanName, mbd, bean) 這個lambda表達式存儲到this.singletonFactories集合中 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } // Initialize the bean instance. Object exposedObject = bean; try { //在這里就會進行屬性填充,完成成員注入等等,也就是在這里serviceA這個bean會注入serviceB這個成員屬性,我們走進這個方法去看看 populateBean(beanName, mbd, instanceWrapper); ...... } ...... return exposedObject;}

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) { ...... if (hasInstAwareBpps) { if (pvs == null) { pvs = mbd.getPropertyValues(); } //真正的屬性注入是在這里完成的,aop也是在這里來完成的。這里是獲取beanFactory中的InstantiationAwareBeanPostProcessor對bean對象進行增強 //如果屬性注入用的是@Resource,就會用CommonAnnotationBeanPostProcessor來完成 //如果屬性注入用的是@Autowired,就會用AutowiredAnnotationBeanPostProcessor來完成 //如果是AOP 就會使用InfrastructureAdvisorAutoProxyCreator來生成對應的代理對象 //我們這里使用的是@Autowired,所以會用AutowiredAnnotationBeanPostProcessor來完成注入。我們走到它的postProcessProperties的去看看 for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) { PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName); ...... }

@Override public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {//這里主要是獲取bean的類屬性和方法上的org.springframework.beans.factory.annotation.Autowired,org.springframework.beans.factory.annotation.Value注解來進行注入 InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs); try { //繼續進去看看 metadata.inject(bean, beanName, pvs); } ...... }

public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable { ...... //對每一個屬性分別進行注入,繼續進去 element.inject(target, beanName, pvs); } }}

@Override protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable { Field field = (Field) this.member; Object value; //如果之前緩存過就從緩存取,我們是第一次注入,所以之前沒有緩存,不會走這個分支 if (this.cached) { try { value = resolvedCachedArgument(beanName, this.cachedFieldValue); } catch (NoSuchBeanDefinitionException ex) { // Unexpected removal of target bean for cached argument -> re-resolve value = resolveFieldValue(field, bean, beanName); } } else { //會走這里來解析字段的值,再進去 value = resolveFieldValue(field, bean, beanName); } if (value != null) { ReflectionUtils.makeAccessible(field); field.set(bean, value); } }

@Nullable private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) { //創建字段的包裝類DependencyDescriptor DependencyDescriptor desc = new DependencyDescriptor(field, this.required); try { //調用這里完成對應字段值的查找,再進去 value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter); } catch (BeansException ex) { throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex); } synchronized (this) { //獲取到值之后,進行緩存 if (!this.cached) { ...... } this.cachedFieldValue = cachedFieldValue; this.cached = true; } } return value; } }

public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException { descriptor.initParameterNameDiscovery(getParameterNameDiscoverer()); if (Optional.class == descriptor.getDependencyType()) { return createOptionalDependency(descriptor, requestingBeanName); } else if (ObjectFactory.class == descriptor.getDependencyType() || ObjectProvider.class == descriptor.getDependencyType()) { return new DependencyObjectProvider(descriptor, requestingBeanName); } else if (javaxInjectProviderClass == descriptor.getDependencyType()) { return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName); } else { //當前的類是一個普通的class,會走到這里面,由于我們的bean沒有Lazy注解,所以這里返回時null,走到下面的if分支 Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary( descriptor, requestingBeanName); if (result == null) { //在這里我們看下這里的入參。 //descriptor是包含了需要注入的字段的信息。 //requestingBeanName是當前正在創建的bean的名字serviceA, //autowiredBeanNames是當前需要注入的字段的對應的bean的名字的集合,這里只有serviceB //typeConverter這個是進行注入時做類型轉換的,這里我們可以不用關注這個 result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter); } return result; } }

@Nullable public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException { ...... if (instanceCandidate instanceof Class) { //又會調用到這里,我們再進入到DependencyDescriptor的resolveCandidate去看看//注意:這里的autowiredBeanName是我們需要注入的屬性名這里是serviceB instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this); } ...... }

public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory) throws BeansException { //看到沒,到這里就出現循環調用了,到這里又會重新調用beanFactory.getBean('serviceB')去創建serviceB的bean對象,完成后注入到serivceA對應的Bean上的屬性上來,這時代碼又會從本節開頭的位置開始執行,先創建serviceB對象實例,再去注入serviceB對象的serviceA屬性。//最終會執行到beanFactory.getBean('serviceA')這里 return beanFactory.getBean(beanName); }

就是下面圖的樣子

springboot bean循環依賴實現以及源碼分析

3、解決循環依賴的代碼實現

接著上面的beanFactory.getBean('serviceA')這行代碼我們繼續往下看

這次又會走到這里

protected <T> T doGetBean( String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException { //我們第二部分就是從這里開始的,又走回來了,但這次又會有所不同 String beanName = transformedBeanName(name); Object beanInstance; // Eagerly check singleton cache for manually registered singletons. //這次我們這里返回的就不是空了,sharedInstance對象的值就是對應serviceA的bean對象了,這次就會從if分支中返回,而之前我們不會進這里的if分支而是進入else分支導致后面出現了循環依賴的問題,這次我們進到這個方法看看 Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { if (logger.isTraceEnabled()) { if (isSingletonCurrentlyInCreation(beanName)) { logger.trace('Returning eagerly cached instance of singleton bean ’' + beanName + '’ that is not fully initialized yet - a consequence of a circular reference'); } else { logger.trace('Returning cached instance of singleton bean ’' + beanName + '’'); } } beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null); }

@Nullable public Object getSingleton(String beanName) { //再點進去 return getSingleton(beanName, true); }

protected Object getSingleton(String beanName, boolean allowEarlyReference) { // Quick check for existing instance without full singleton lock Object singletonObject = this.singletonObjects.get(beanName); //這里由于當前的serviceA bean還沒完成創建,所以這里singletonObject返回的是空,//再看看 isSingletonCurrentlyInCreation(beanName)這里,由于我們在創建serviceA過程中有這么一句beforeSingletonCreation(beanName)(不清楚這句的搜索下本文,上面就有講到),所有這個條件是true。這時我們就會進入if分支中 if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { singletonObject = this.earlySingletonObjects.get(beanName); //由于我們是第一次進入這里,所以this.earlySingletonObjects.get(beanName)返回的也是null //我們的入參 allowEarlyReference是true,會繼續進到這個if分支中 if (singletonObject == null && allowEarlyReference) { synchronized (this.singletonObjects) { // Consistent creation of early reference within full singleton lock singletonObject = this.singletonObjects.get(beanName); //這里的singletonObject還是null,繼續進到if分支 if (singletonObject == null) { singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null) { //最終會走到這里,在創建serviceA對象之后,屬性注入之前,執行了這句 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean))(不清楚的搜索下本文,上面有說到),所以這里返回的singletonFactory是個lamdba表達式,getEarlyBeanReference(beanName, mbd, bean))附帶了3個參數,第一個beanName是serivceA,mdb是對應serviceA的附帶serviceA元數據信息的RootBeanDefinition對象,bean就是創建出來的serviceA對象 ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) {//這里就會調用getEarlyBeanReference(beanName, mbd, bean)對serviceA對象進行一個getEarlyBeanReference增強后返回,返回后放置到earlySingletonObjects中,并從singletonFactories中刪除singletonObject = singletonFactory.getObject();this.earlySingletonObjects中,并從.put(beanName, singletonObject);this.singletonFactories.remove(beanName); } } } } } } return singletonObject; }

最終在serviceA 這個bean創建完成后,就會從singletonsCurrentlyInCreation移除掉

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { ...... finally { //在這里從singletonsCurrentlyInCreation中移除掉 afterSingletonCreation(beanName); } if (newSingleton) { //將serviceA bean對象添加到singletonObjects,registeredSingletons中 //從singletonFactories,earlySingletonObjects中移除掉 addSingleton(beanName, singletonObject); } } return singletonObject; } }

所以整個獲取serviceA的流程就是這樣了,

1、首先去創建serviceA這個bean,

由于它有個屬性serviceB,在創建完serviceA對象后,就會去進行serviceB的屬性注入, 這時由于serviceB之前沒有生成,這時又會去創建serviceB這個bean, 先創建serviceB對象,然后再進行serviceA這個屬性的注入, 繼續去獲取serviceA這個bean,第二次進入獲取serviceA的流程,這時從之前緩存的lambda表達式中獲取到之前創建的serviceA的引用返回。

2、總結下關鍵的代碼點

創建bean對象之前調用beforeSingletonCreation(beanName)將bean對象名字添加到singletonsCurrentlyInCreation集合中 創建bean對象對應的類實例后調用addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));添加到singletonFactories中 在循環依賴中第二次調用到創建bean對象時,調用getSingleton(beanName, true)時,從singletonFactories中返回對應的早期bean對象的引用,并添加到earlySingletonObjects中總結

到此這篇關于springboot bean循環依賴實現以及源碼分析的文章就介紹到這了,更多相關springboot bean循環依賴內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!

標簽: Spring
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
精品视频一区二区三区四区五区| 欧美专区18| 涩涩涩久久久成人精品| 亚洲精品第一| 欧美亚洲综合视频| 欧美a一区二区| 日韩欧美二区| 亚洲欧美日本日韩| 欧美日韩亚洲三区| 国产欧美大片| 久久精品一区二区三区中文字幕| 电影91久久久| 久久福利一区| 国产一区二区三区不卡视频网站 | 日韩精品一级| 91综合久久爱com| 精品欧美一区二区三区在线观看| 久久国产直播| 亚洲精品三级| 欧洲av不卡| 日本视频中文字幕一区二区三区| 日韩在线观看不卡| 亚洲精品欧洲| 1000部精品久久久久久久久| 国产欧美激情| 麻豆9191精品国产| 1024精品一区二区三区| 精品视频亚洲| 国产日韩一区二区三免费高清| 日韩中文影院| 成人台湾亚洲精品一区二区| 亚洲精品一级| 欧美aa在线观看| 欧美片第1页综合| 日韩国产在线观看一区| 欧美日韩四区| 黑丝美女一区二区| 好看不卡的中文字幕| 在线一区欧美| 亚洲aa在线| 久久免费黄色| 丰满少妇一区| 少妇精品久久久一区二区| 欧美aa在线观看| 精品一区二区三区免费看| 国产精品日韩久久久| 国产福利资源一区| 久久国产精品久久久久久电车| 美女高潮久久久| 国产精品一区二区美女视频免费看| 亚洲欧美日本日韩| 精品在线99| 日韩理论片av| 国语对白精品一区二区| 欧美在线91| 国产探花在线精品| 日韩精品免费视频一区二区三区| 国产精品老牛| 麻豆9191精品国产| 丝袜脚交一区二区| 蜜乳av另类精品一区二区| 91久久久精品国产| 欧美日韩精品一区二区视频| 亚洲一级少妇| 夜夜嗨网站十八久久| 西西人体一区二区| 中文一区一区三区免费在线观| 蜜臀久久久久久久| 亚洲最新av| 国产探花在线精品| 国产精品久久久久久久免费观看 | 国产欧美二区| 麻豆久久一区二区| 欧美激情视频一区二区三区在线播放| 你懂的国产精品| 日韩不卡免费高清视频| 午夜久久99| 欧美午夜三级| 超碰99在线| 在线日韩中文| 亚洲欧美一级| 国产成人免费视频网站视频社区| 水蜜桃精品av一区二区| 九九久久婷婷| 在线看片日韩| 久久爱www成人| 欧美日韩高清| 91精品国产自产精品男人的天堂| 国产精品毛片视频| 激情综合自拍| 国产精品一在线观看| 1000部精品久久久久久久久| 日韩精品三级| 激情亚洲影院在线观看| 日本精品另类| 欧美 日韩 国产精品免费观看| 婷婷久久免费视频| 久久电影tv| 欧美久久一区二区三区| 久久久水蜜桃av免费网站| 日韩一二三区在线观看| 91精品国产成人观看| 欧美中文高清| 亚洲一级二级| 精品资源在线| 亚洲精品亚洲人成在线观看| 久久婷婷一区| 欧美精品97| 日本成人中文字幕在线视频| 日本精品在线中文字幕| 国产精品一区毛片| 日韩一区欧美二区| 欧洲激情综合| 999国产精品| а√天堂8资源中文在线| 欧美一区91| 欧美一级二级视频| 日本一不卡视频| 99亚洲精品| 99国产精品免费视频观看| 国产极品久久久久久久久波多结野| 日韩视频一二区| 麻豆亚洲精品| 亚洲色图网站| 视频一区在线播放| 国产精品三上| 蜜臀av一区二区三区| 亚洲综合丁香| 亚洲三级国产| 日本v片在线高清不卡在线观看| 在线精品福利| 7777精品| 麻豆国产精品| 精品一区视频| 98精品视频| 在线一区免费观看| 色综合视频一区二区三区日韩| 日韩精品福利一区二区三区| 日韩av午夜在线观看| 国产精品欧美一区二区三区不卡 | 免费一级欧美片在线观看网站 | 男女精品网站| 国产日产一区| 精品国产精品久久一区免费式| www.51av欧美视频| 久久久久中文| 日韩中文字幕av电影| 日韩三级精品| 国产精品igao视频网网址不卡日韩| 国产精品视频一区视频二区| 中文在线免费视频| 午夜一级久久| 国产精久久久| 欧美日韩激情| 青青草国产精品亚洲专区无| 国产伦理久久久久久妇女| 国产精成人品2018| 日韩三区免费| 美国三级日本三级久久99| 国产精品大片| 国产一区二区三区自拍| 日韩激情一区二区| 色婷婷色综合| 久久www成人_看片免费不卡| 麻豆精品视频在线观看免费| 麻豆精品蜜桃| 欧美日韩a区| 亚洲尤物在线| 麻豆成人av在线| 在线视频精品| 精品三级久久久| 伊人影院久久| 91看片一区| 国产精品毛片aⅴ一区二区三区| 日韩精品午夜| 国产乱子精品一区二区在线观看| 影音先锋国产精品| 麻豆精品久久久| 日韩一区欧美二区| 激情久久久久久久| 麻豆国产精品| 久久精品av麻豆的观看方式| 欧美美女一区| 99久久视频| 国产成年精品| 欧美日韩一区二区三区四区在线观看| 久久精品青草| 成人日韩av| 国产麻豆一区二区三区| 亚洲精品成a人ⅴ香蕉片| 中文日韩在线| 欧美成人综合| se01亚洲视频| 久久久久久久久久久妇女| 久久婷婷国产| 成人精品国产亚洲| 深夜福利视频一区二区| 精品亚洲成人| 高清一区二区| 加勒比视频一区|