溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

SpringBean循環(huán)依賴(lài)問(wèn)題的解決方法

發(fā)布時(shí)間:2021-10-21 09:38:01 來(lái)源:億速云 閱讀:114 作者:柒染 欄目:大數(shù)據(jù)

本篇文章給大家分享的是有關(guān)SpringBean循環(huán)依賴(lài)問(wèn)題的解決方法,小編覺(jué)得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話(huà)不多說(shuō),跟著小編一起來(lái)看看吧

Spring循環(huán)依賴(lài)

什么是Spring的循環(huán)依賴(lài)?循環(huán)依賴(lài)會(huì)存在哪些問(wèn)題?

示例:AService依賴(lài)BService; BService依賴(lài)AService

@Service
public class AService {
    //
    @Autowired
    public BService bService;
}
@Service
public class BService {
    @Autowired
    public AService aService;
}

SpringBean循環(huán)依賴(lài)問(wèn)題的解決方法

Spring中的循環(huán)依賴(lài)問(wèn)題在單例的情況下,Spring是已經(jīng)幫我們解決好了,多例沒(méi)有解決循環(huán)依賴(lài)問(wèn)題。

為啥,多例的情況下 Spring沒(méi)有去解決循環(huán)依賴(lài)問(wèn)題?

因?yàn)樵诙嗬那闆r下,設(shè)置的多例的對(duì)象沒(méi)有明確哪一個(gè),就會(huì)產(chǎn)生循環(huán)依賴(lài)問(wèn)題。

Spring多例我們要:如何解決循環(huán)依賴(lài)問(wèn)題?

我們可以自己去:明確指定引用那個(gè)對(duì)象

@Service
@Scope("prototype")
public class AService {
   // @Autowired
    public BService bService;
    // 為什么Aservice在創(chuàng)建的時(shí)候 為什么Bservice比ASERVICE 先創(chuàng)建
    public AService() {
        System.out.println("AService被Java的反射技術(shù)創(chuàng)建");
    }
    public void setbService(BService bService) {
        this.bService = bService;
    }

}
@Service
@Scope("prototype")
public class BService {
   // @Autowired
    public AService aService;

    public void setaService(AService aService) {
        this.aService = aService;
    }
}
public class SpringApp {
    public static void main(String[] args) {
//        1. ioc容器在創(chuàng)建的時(shí)候所有的單例對(duì)象是不是會(huì)被創(chuàng)建
       AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
//        // 對(duì)例子情況 當(dāng)你在調(diào)用的時(shí)候才獲取
        AService aSerivce = applicationContext.getBean("AService", AService.class);
        BService bSerivce = applicationContext.getBean("BService", BService.class);
        aSerivce.setbService(bSerivce);
        bSerivce.setaService(aSerivce);
        // 循環(huán)引用異常 找不到對(duì)象
        /**
         * 思考問(wèn)題? 如果我們的項(xiàng)目對(duì)象必須要是多例? 而且必須要循環(huán)引用  明確的指定引用那個(gè)對(duì)象
         */
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (int i = 0; i < beanDefinitionNames.length; i++) {
            System.out.println(beanDefinitionNames[i]);
        }

SpringBean循環(huán)依賴(lài)問(wèn)題的解決方法

SpringBean循環(huán)依賴(lài)三級(jí)緩存概念

思考問(wèn)題:?jiǎn)卫龑?duì)象在什么時(shí)候創(chuàng)建?

在IOC容器被創(chuàng)建的時(shí)候創(chuàng)建

多例的情況下,是在getbean()調(diào)用的情況下創(chuàng)建。多例對(duì)象每次用完就會(huì)去銷(xiāo)毀掉。

SpringBean Aservice對(duì)象被創(chuàng)建流程步驟源碼分析

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);

SpringBean循環(huán)依賴(lài)問(wèn)題的解決方法

// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();

SpringBean循環(huán)依賴(lài)問(wèn)題的解決方法

public Object getBean(String name) throws BeansException {
    return this.doGetBean(name, (Class)null, (Object[])null, false);
}

SpringBean循環(huán)依賴(lài)問(wèn)題的解決方法

public Object getSingleton(String beanName) {
    return this.getSingleton(beanName, true);
}

獲取緩存對(duì)象:

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    Object singletonObject = this.singletonObjects.get(beanName);    //根據(jù)BeanName去集合中查,查到就返回這個(gè)對(duì)象,【】【】【】一級(jí)緩存對(duì)象集合【】【】【】緩存完整對(duì)象【】【】完整對(duì)象表示對(duì)象已經(jīng)創(chuàng)建完了,并且對(duì)象屬性已經(jīng)賦值了。
    if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
        Map var4 = this.singletonObjects;
        synchronized(this.singletonObjects) {
            singletonObject = this.earlySingletonObjects.get(beanName);    //查詢(xún)二級(jí)緩存中是否有緩存對(duì)象
            if (singletonObject == null && allowEarlyReference) {
                ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);    //查詢(xún)?nèi)?jí)緩存,三級(jí)緩存中有的化,將三級(jí)緩存中的數(shù)據(jù)放入二級(jí)緩存中
                if (singletonFactory != null) {
                    singletonObject = singletonFactory.getObject();
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}

SpringBean循環(huán)依賴(lài)問(wèn)題的解決方法

SpringBean循環(huán)依賴(lài)問(wèn)題的解決方法

一級(jí)緩存沒(méi)有找到,就去找二級(jí)緩存中找

SpringBean循環(huán)依賴(lài)問(wèn)題的解決方法

singletonObject == null && this.isSingletonCurrentlyInCreation(beanName) //一級(jí)緩存沒(méi)有,并且singletonsCurrentlyInCreation判斷是否之前標(biāo)記為該對(duì)象開(kāi)始創(chuàng)建

SpringBean循環(huán)依賴(lài)問(wèn)題的解決方法

SpringBean循環(huán)依賴(lài)問(wèn)題的解決方法

if (isPrototypeCurrentlyInCreation(beanName)) { //我們對(duì)象是單例的,所有不進(jìn)入
   throw new BeanCurrentlyInCreationException(beanName);
}

SpringBean循環(huán)依賴(lài)問(wèn)題的解決方法

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
   Assert.notNull(beanName, "Bean name must not be null");
   synchronized (this.singletonObjects) {
      Object singletonObject = this.singletonObjects.get(beanName);
      if (singletonObject == null) {
         if (this.singletonsCurrentlyInDestruction) {
            throw new BeanCreationNotAllowedException(beanName,
                  "Singleton bean creation not allowed while singletons of this factory are in destruction " +
                  "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
         }
         if (logger.isDebugEnabled()) {
            logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
         }
         beforeSingletonCreation(beanName);
         boolean newSingleton = false;
         boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
         if (recordSuppressedExceptions) {
            this.suppressedExceptions = new LinkedHashSet<>();
         }
         try {
            singletonObject = singletonFactory.getObject();
            newSingleton = true;
         }
         catch (IllegalStateException ex) {
            // Has the singleton object implicitly appeared in the meantime ->
            // if yes, proceed with it since the exception indicates that state.
            singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
               throw ex;
            }
         }
         catch (BeanCreationException ex) {
            if (recordSuppressedExceptions) {
               for (Exception suppressedException : this.suppressedExceptions) {
                  ex.addRelatedCause(suppressedException);
               }
            }
            throw ex;
         }
         finally {
            if (recordSuppressedExceptions) {
               this.suppressedExceptions = null;
            }
            afterSingletonCreation(beanName);
         }
         if (newSingleton) {
            addSingleton(beanName, singletonObject);
         }
      }
      return singletonObject;
   }
}

SpringBean循環(huán)依賴(lài)問(wèn)題的解決方法

protected void beforeSingletonCreation(String beanName) {
   if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
      throw new BeanCurrentlyInCreationException(beanName);
   }
}

標(biāo)識(shí)為該對(duì)象開(kāi)始創(chuàng)建

SpringBean循環(huán)依賴(lài)問(wèn)題的解決方法

最終調(diào)用

SpringBean循環(huán)依賴(lài)問(wèn)題的解決方法

正真去創(chuàng)建我們的Bean對(duì)象:

SpringBean循環(huán)依賴(lài)問(wèn)題的解決方法

既然要?jiǎng)?chuàng)建對(duì)象,先反射走無(wú)參構(gòu)造函數(shù),對(duì)象先實(shí)例化完成,在賦值

SpringBean循環(huán)依賴(lài)問(wèn)題的解決方法

執(zhí)行這個(gè)方法,輸出構(gòu)造函數(shù)打印的語(yǔ)句,說(shuō)明底層通過(guò)Java反射機(jī)制初始化的

SpringBean循環(huán)依賴(lài)問(wèn)題的解決方法

在這之前,我們的對(duì)象屬于嬰兒對(duì)象,因?yàn)樗膶傩赃€沒(méi)有賦值。都是稱(chēng)為嬰兒對(duì)象。

那么什么時(shí)候賦值呢?

SpringBean循環(huán)依賴(lài)問(wèn)題的解決方法

populateBean(beanName, mbd, instanceWrapper);//這里給對(duì)象屬性賦值

在給對(duì)象屬性賦值之前:

SpringBean循環(huán)依賴(lài)問(wèn)題的解決方法

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
   Assert.notNull(singletonFactory, "Singleton factory must not be null");
   synchronized (this.singletonObjects) {
      if (!this.singletonObjects.containsKey(beanName)) {    //【】【】如果一級(jí)緩存沒(méi)有該對(duì)象的情況下,會(huì)將該對(duì)象存放在三級(jí)緩存中
         this.singletonFactories.put(beanName, singletonFactory);    //【】【】存放在三級(jí)緩存中,對(duì)象實(shí)例化完成,但是沒(méi)有賦值,嬰兒對(duì)象【】【】
         this.earlySingletonObjects.remove(beanName);
         this.registeredSingletons.add(beanName);
      }
   }
}

SpringBean循環(huán)依賴(lài)問(wèn)題的解決方法

SpringBean循環(huán)依賴(lài)問(wèn)題的解決方法

A對(duì)象堅(jiān)持依賴(lài)B對(duì)象,這時(shí)候B對(duì)象也需要被創(chuàng)建

A對(duì)象已經(jīng)存放在三級(jí)緩存中,這時(shí)候要去創(chuàng)建B對(duì)象

此時(shí)B對(duì)象也要走A對(duì)象流程

SpringBean循環(huán)依賴(lài)問(wèn)題的解決方法

看下調(diào)用鏈

SpringBean循環(huán)依賴(lài)問(wèn)題的解決方法

SpringBean循環(huán)依賴(lài)問(wèn)題的解決方法

SpringBean循環(huán)依賴(lài)問(wèn)題的解決方法

也將B對(duì)象放入三級(jí)緩存

SpringBean循環(huán)依賴(lài)問(wèn)題的解決方法

SpringBean循環(huán)依賴(lài)問(wèn)題的解決方法

總結(jié)下:

AService在創(chuàng)建的時(shí)候,提前曝光存放到三級(jí)緩存中,AService發(fā)現(xiàn)依賴(lài)BService,這時(shí)候Bservice提前曝光存放到三級(jí)緩存中去。

此時(shí)BService又依賴(lài)AService,此時(shí)BService經(jīng)過(guò)賦值是完整對(duì)象,但是Aservice還是嬰兒對(duì)象,沒(méi)有完全創(chuàng)建完畢。

就會(huì)去把BService對(duì)象注冊(cè)到一級(jí)緩存中,同時(shí)會(huì)把之前緩存BService對(duì)象的二級(jí)緩存清除掉

AService對(duì)象依賴(lài)BService,BService此時(shí)已經(jīng)創(chuàng)建成功了,那么AService在設(shè)置屬性后,就直接把BService賦值給AService。

開(kāi)始注冊(cè)AService對(duì)象

SpringBean循環(huán)依賴(lài)問(wèn)題的解決方法

SpringBean循環(huán)依賴(lài)問(wèn)題的解決方法

總結(jié):

 SpringBean中 Aservic對(duì)象被創(chuàng)建流程步驟源碼分析:

  1. doGetBean創(chuàng)建我們bean對(duì)象

  2. getSingleton (beanName) 獲取緩存對(duì)象

注意:完整對(duì)象概念:對(duì)象已經(jīng)實(shí)例化成功并且所有屬性都已經(jīng)賦值

  • singletonObjects 一級(jí)緩存完整對(duì)象

  • earlySingletonObjects 二級(jí)緩存 緩存嬰兒對(duì)象

  • singletonFactories 三級(jí)緩存存放嬰兒對(duì)象

理解概念:

  1. 完整對(duì)象表示該對(duì)象實(shí)例化完成并且所有的屬性已經(jīng)賦值。

  2. 嬰兒對(duì)象(提前對(duì)象)對(duì)象已經(jīng)實(shí)例化完成但是屬性沒(méi)有賦值的。

singletonObject ==null&&this.singletonsCurrentlyInCreation.contains(beanName);

{

才能夠查詢(xún)二級(jí)緩存

}
singletonsCurrentlyInCreation :標(biāo)記為該對(duì)象開(kāi)始創(chuàng)建

  1. getSingleton(String beanName, ObjectFactory<?> singletonFactory)

this.singletonsCurrentlyInCreation.add(beanName) 表示該對(duì)象已經(jīng)開(kāi)始創(chuàng)建

  1. createBean() →doCreateBean

  2. addSingletonFactory  將嬰兒對(duì)象(不完整對(duì)象也就是只是實(shí)例化完成但是屬性沒(méi)有賦值的) 存放三級(jí)緩存中。

  3. A對(duì)象已經(jīng)存放到三級(jí)緩存中,開(kāi)始給對(duì)象屬性賦值的時(shí)候 需要?jiǎng)?chuàng)建B對(duì)象。

A對(duì)象檢查發(fā)現(xiàn)依賴(lài)B對(duì)象 這時(shí)候B對(duì)象也需要被創(chuàng)建

以上就是SpringBean循環(huán)依賴(lài)問(wèn)題的解決方法,小編相信有部分知識(shí)點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見(jiàn)到或用到的。希望你能通過(guò)這篇文章學(xué)到更多知識(shí)。更多詳情敬請(qǐng)關(guān)注億速云行業(yè)資訊頻道。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI