示例:AService依賴BService; BService依賴AService緩存
@Service public class AService { // @Autowired public BService bService; }
@Service public class BService { @Autowired public AService aService; }
上面演示的例子就是循環注入app
若是改成多例的化,運行時就會報錯,循環引用異常,找不到對象函數
@Scope("prototype")
Spring中的循環依賴問題在單例的狀況下,Spring是已經幫咱們解決好了,多例沒有解決循環依賴問題。源碼分析
爲啥,多例的狀況下 Spring沒有去解決循環依賴問題?this
由於在多例的狀況下,設置的多例的對象沒有明確哪個,就會產生循環依賴問題。spa
咱們能夠本身去:明確指定引用那個對象prototype
@Service @Scope("prototype") public class AService { // @Autowired public BService bService; // 爲何Aservice在建立的時候 爲何Bservice比ASERVICE 先建立 public AService() { System.out.println("AService被Java的反射技術建立"); } 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容器在建立的時候全部的單例對象是否是會被建立 AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class); // // 對例子狀況 當你在調用的時候才獲取 AService aSerivce = applicationContext.getBean("AService", AService.class); BService bSerivce = applicationContext.getBean("BService", BService.class); aSerivce.setbService(bSerivce); bSerivce.setaService(aSerivce); // 循環引用異常 找不到對象 /** * 思考問題? 若是咱們的項目對象必需要是多例? 並且必需要循環引用 明確的指定引用那個對象 */ String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames(); for (int i = 0; i < beanDefinitionNames.length; i++) { System.out.println(beanDefinitionNames[i]); }
思考問題:單例對象在何時建立?debug
在IOC容器被建立的時候建立3d
多例的狀況下,是在getbean()調用的狀況下建立。多例對象每次用完就會去銷燬掉。對象
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
// Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory);
// Instantiate all remaining (non-lazy-init) singletons. beanFactory.preInstantiateSingletons();
public Object getBean(String name) throws BeansException { return this.doGetBean(name, (Class)null, (Object[])null, false); }
public Object getSingleton(String beanName) { return this.getSingleton(beanName, true); }
獲取緩存對象:
protected Object getSingleton(String beanName, boolean allowEarlyReference) { Object singletonObject = this.singletonObjects.get(beanName); //根據BeanName去集合中查,查到就返回這個對象,【】【】【】一級緩存對象集合【】【】【】緩存完整對象【】【】完整對象表示對象已經建立完了,而且對象屬性已經賦值了。 if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) { Map var4 = this.singletonObjects; synchronized(this.singletonObjects) { singletonObject = this.earlySingletonObjects.get(beanName); //查詢二級緩存中是否有緩存對象 if (singletonObject == null && allowEarlyReference) { ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName); //查詢三級緩存,三級緩存中有的化,將三級緩存中的數據放入二級緩存中 if (singletonFactory != null) { singletonObject = singletonFactory.getObject(); this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } return singletonObject; }
一級緩存沒有找到,就去找二級緩存中找
singletonObject == null && this.isSingletonCurrentlyInCreation(beanName) //一級緩存沒有,而且singletonsCurrentlyInCreation判斷是否以前標記爲該對象開始建立
if (isPrototypeCurrentlyInCreation(beanName)) { //咱們對象是單例的,全部不進入 throw new BeanCurrentlyInCreationException(beanName); }
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; } }
protected void beforeSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } }
標識爲該對象開始建立
最終調用
正真去建立咱們的Bean對象:
既然要建立對象,先反射走無參構造函數,對象先實例化完成,在賦值
執行這個方法,輸出構造函數打印的語句,說明底層經過Java反射機制初始化的
在這以前,咱們的對象屬於嬰兒對象,由於它的屬性尚未賦值。都是稱爲嬰兒對象。
那麼何時賦值呢?
populateBean(beanName, mbd, instanceWrapper);//這裏給對象屬性賦值
在給對象屬性賦值以前:
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(singletonFactory, "Singleton factory must not be null"); synchronized (this.singletonObjects) { if (!this.singletonObjects.containsKey(beanName)) { //【】【】若是一級緩存沒有該對象的狀況下,會將該對象存放在三級緩存中 this.singletonFactories.put(beanName, singletonFactory); //【】【】存放在三級緩存中,對象實例化完成,可是沒有賦值,嬰兒對象【】【】 this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } } }
A對象堅持依賴B對象,這時候B對象也須要被建立
A對象已經存放在三級緩存中,這時候要去建立B對象
此時B對象也要走A對象流程
看下調用鏈
也將B對象放入三級緩存
總結下:
AService在建立的時候,提早曝光存放到三級緩存中,AService發現依賴BService,這時候Bservice提早曝光存放到三級緩存中去。
此時BService又依賴AService,此時BService通過賦值是完整對象,可是Aservice仍是嬰兒對象,沒有徹底建立完畢。
就會去把BService對象註冊到一級緩存中,同時會把以前緩存BService對象的二級緩存清除掉
AService對象依賴BService,BService此時已經建立成功了,那麼AService在設置屬性後,就直接把BService賦值給AService。
開始註冊AService對象
SpringBean中 Aservic對象被建立流程步驟源碼分析:
- doGetBean建立咱們bean對象
- getSingleton (beanName) 獲取緩存對象
注意:完整對象概念:對象已經實例化成功而且全部屬性都已經賦值
- singletonObjects 一級緩存完整對象
- earlySingletonObjects 二級緩存 緩存嬰兒對象
- singletonFactories 三級緩存存放嬰兒對象
理解概念:
- 完整對象表示該對象實例化完成而且全部的屬性已經賦值。
- 嬰兒對象(提早對象)對象已經實例化完成可是屬性沒有賦值的。
singletonObject ==null&&this.singletonsCurrentlyInCreation.contains(beanName);
{
纔可以查詢二級緩存
}
singletonsCurrentlyInCreation :標記爲該對象開始建立
- getSingleton(String beanName, ObjectFactory<?> singletonFactory)
this.singletonsCurrentlyInCreation.add(beanName) 表示該對象已經開始建立
- createBean() →doCreateBean
- addSingletonFactory 將嬰兒對象(不完整對象也就是隻是實例化完成可是屬性沒有賦值的) 存放三級緩存中。
- A對象已經存放到三級緩存中,開始給對象屬性賦值的時候 須要建立B對象。
A對象檢查發現依賴B對象 這時候B對象也須要被建立
本文參考:
螞蟻課堂