菜瓜:水稻,此次我特地去看了java的循環依賴java
水稻:喲,有什麼收穫spring
菜瓜:兩種狀況,構造器循環依賴,屬性循環依賴緩存
package club.interview.base; /** * 構造器循環依賴 - Exception in thread "main" java.lang.StackOverflowError * toString()循環打印也會異常 - Exception in thread "main" java.lang.StackOverflowError * @author QuCheng on 2020/6/18. */ public class Circular { class A { B b; // public A() { // b = new B(); // } // @Override // public String toString() { // return "A{" + // "b=" + b + // '}'; // } } class B { A a; // public B() { // a = new A(); // } // @Override // public String toString() { // return "B{" + // "a=" + a + // '}'; // } } private void test() { B b = new B(); A a = new A(); a.b = b; b.a = a; System.out.println(a); System.out.println(b); } public static void main(String[] args) { new Circular().test(); } }
水稻:厲害啊,Spring也不支持構造函數的依賴注入,並且也不支持多例的循環依賴。一樣的,它支持屬性的依賴注入。app
package com.vip.qc.circular; import org.springframework.stereotype.Component; import javax.annotation.Resource; /** * @author QuCheng on 2020/6/18. */ @Component("a") public class CircularA { @Resource private CircularB circularB; // @Override // public String toString() { // return "CircularA{" + // "circularB=" + circularB + // '}'; // } } package com.vip.qc.circular; import org.springframework.stereotype.Component; import javax.annotation.Resource; /** * @author QuCheng on 2020/6/18. */ @Component("b") public class CircularB { @Resource private CircularA circularA; // @Override // public String toString() { // return "CircularB{" + // "circularA=" + circularA + // '}'; // } } @Test public void testCircular() { String basePackages = "com.vip.qc.circular"; new AnnotationConfigApplicationContext(basePackages); }
菜瓜:看來spring的實現應該也是經過屬性注入的吧ide
水稻:你說的對。先給思路和demo,以後帶你掃一遍源碼,follow me !函數
爲了證明結果,我把源碼給改了一下,看結果測試
package com.vip.qc.circular; import org.springframework.stereotype.Component; import javax.annotation.Resource; /** * @author QuCheng on 2020/6/18. */ @Component("a") public class CircularA { @Resource private CircularB circularB; @Override public String toString() { return "CircularA{" + "circularB=" + circularB + '}'; } } package com.vip.qc.circular; import org.springframework.stereotype.Component; import javax.annotation.Resource; /** * @author QuCheng on 2020/6/18. */ @Component("b") public class CircularB { @Resource private CircularA circularA; @Override public String toString() { return "CircularB{" + "circularA=" + circularA + '}'; } } 測試代碼 @Test public void testCircular() { String basePackages = "com.vip.qc.circular"; new AnnotationConfigApplicationContext(basePackages); } 測試結果(我改過源碼了) ---- 將a放入三級緩存 將b放入三級緩存 將a放入二級緩存 將b放入一級緩存 從二級緩存中拿到了a 將a放入一級緩存
public class DefaultSingletonBeanRegistry /** 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);
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { /** * 處理FactoryBean接口名稱轉換 {@link BeanFactory#FACTORY_BEAN_PREFIX } */ final String beanName = transformedBeanName(name); ... // ①從緩存中拿對象(若是對象正在建立中且被依賴注入,會放入二級緩存) Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { ... }else { ... if (mbd.isSingleton()) { // ② 將建立的對象放入一級緩存 sharedInstance = getSingleton(beanName, () -> { try { // ③ 具體建立的過程,每一個bean建立完成以後都會放入三級緩存,而後渲染屬性 return createBean(beanName, mbd, args); }catch (BeansException ex) { ... ... return (T) bean; }
protected Object getSingleton(String beanName, boolean allowEarlyReference) { // 實例化已經完成了的放在singletonObjects 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); if(beanName.equals("a")||beanName.equals("b")||beanName.equals("c")) System.out.println("將"+beanName+"放入二級緩存");; this.singletonFactories.remove(beanName); } }else if(singletonObject != null){ System.out.println("從二級緩存中拿到了"+beanName); } } } return singletonObject; }
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) { ... // 正在建立的bean加入singletonsCurrentlyInCreation - 保證只有一個對象建立,阻斷循環依賴 beforeSingletonCreation(beanName); ... try { singletonObject = singletonFactory.getObject(); ... finally { ... // 從singletonsCurrentlyInCreation中移除 afterSingletonCreation(beanName); } if (newSingleton) { // 對象建立完畢 - 放入一級緩存(從其餘緩存移除) addSingleton(beanName, singletonObject); } } return singletonObject; } } // ----- 內部調用一級緩存操做 protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { if(beanName.equals("a")||beanName.equals("b")||beanName.equals("c")) System.out.println("將"+beanName+"放入一級緩存");; this.singletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } }
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)throws BeanCreationException { ... if (instanceWrapper == null) { // 5* 實例化對象自己 instanceWrapper = createBeanInstance(beanName, mbd, args); } ... boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { ... // 將建立好還未渲染屬性的bean 放入三級緩存 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } Object exposedObject = bean; try { // 渲染bean自身和屬性 populateBean(beanName, mbd, instanceWrapper); // 實例化以後的後置處理 - init exposedObject = initializeBean(beanName, exposedObject, mbd); } catch (Throwable ex) { ... return exposedObject; } // ------------- 內部調用三級緩存操做 protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(singletonFactory, "Singleton factory must not be null"); synchronized (this.singletonObjects) { if (!this.singletonObjects.containsKey(beanName)) { if(beanName.equals("a")||beanName.equals("b")||beanName.equals("c")) System.out.println("將"+beanName+"放入三級緩存");; this.singletonFactories.put(beanName, singletonFactory); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } } }
菜瓜:demo比較簡單,流程大體明白,源碼我還須要斟酌一下,總體有了概念。這個流程好像是摻雜在bean的建立過程當中,結合bean的生命週期總體理解可能會更深刻一點ui
水稻:是的。每一個知識點都不是單一的,拿着bean的生命週期再理解一遍可能會更有收穫。this
討論spa
總結