1、循環依賴
(1)概念
對象依賴分為強依賴和弱依賴:
強依賴指的是一個對象包含了另外一個對象的引用,例如:學生類中包含了課程類,在學生類中存在課程類的引用
創建課程類:
@Data public class Course { private String cname; private Integer credit; }
創建學生類:
@Data public class Student { private String sname; private int age; private Course course; }
測試類:
public class Test { public static void main(String[] args) { Student student=new Student(); Course course=new Course(); student.setCourse(course); } }
弱依賴指的是一個對象里面調用了另外一個對象
循環依賴:A引用B,而B又引用A
創建課程類,課程類中有學生類的引用:
@Data public class Course { private String cname; private Integer credit; private Student student; }
創建學生類,學生類中存在課程類中的引用:
@Data public class Student { private String sname; private int age; private Course course; }
創建測試類,測試類中學生類調用課程類的對象,課程類的對象又調用學生類的對象:
public class Test { public static void main(String[] args) { Student student=new Student(); Course course=new Course(); student.setCourse(course); course.setStudent(student); } }
測試類可以正常地獲取對象,也就是說這種方式是支持循環依賴的。
(2)spring的循環依賴
<bean id="student" class="com.zhb.bean.Student" scope="singleton"> <property name="course" ref="course"></property> </bean> <bean id="course" class="com.zhb.bean.Course" scope="singleton"> <property name="student" ref="student"></property> </bean>
單例模式下支持,多例模式下不支持
(3)spring是否支持循環依賴
支持
(4)spring的所有對象是不是都支持循環依賴
單例模式下支持:單例模式下是首先創建出兩個對象,然后進行依賴的注入。A注入B,B注入A。
多例模式下不支持:A創建的時候會去判斷是否依賴於其他對象,如果依賴的話就不會去先創建A。創建B的時候也會去判斷是否依賴其他對象,如果A依賴於B,而B又依賴於A的話就會造成一個死循環,兩個對象都不會創建。
2、spring循環依賴的過程
(1)流程
(2)源碼
ClassPathXmlApplicationContext方法:
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException { super(parent); this.setConfigLocations(configLocations); if (refresh) { this.refresh();//refresh方法是真正的創建對象的方法 } }
refresh方法:
public void refresh() throws BeansException, IllegalStateException { synchronized(this.startupShutdownMonitor) { this.prepareRefresh(); ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory(); this.prepareBeanFactory(beanFactory); try { this.postProcessBeanFactory(beanFactory); this.invokeBeanFactoryPostProcessors(beanFactory);//Bean工廠的后置處理器 this.registerBeanPostProcessors(beanFactory); this.initMessageSource(); this.initApplicationEventMulticaster(); this.onRefresh(); this.registerListeners(); this.finishBeanFactoryInitialization(beanFactory);//此方法是真正的創建對象的方法,能夠實例化所有的單例bean this.finishRefresh(); } catch (BeansException var9) { if (this.logger.isWarnEnabled()) { this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9); } this.destroyBeans(); this.cancelRefresh(var9); throw var9; } finally { this.resetCommonCaches(); } } }
finishBeanFactoryInitialization
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { if (beanFactory.containsBean("conversionService") && beanFactory.isTypeMatch("conversionService", ConversionService.class)) { beanFactory.setConversionService((ConversionService)beanFactory.getBean("conversionService", ConversionService.class)); } if (!beanFactory.hasEmbeddedValueResolver()) { beanFactory.addEmbeddedValueResolver((strVal) -> { return this.getEnvironment().resolvePlaceholders(strVal); }); } String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false); String[] var3 = weaverAwareNames; int var4 = weaverAwareNames.length; for(int var5 = 0; var5 < var4; ++var5) { String weaverAwareName = var3[var5]; this.getBean(weaverAwareName); } beanFactory.setTempClassLoader((ClassLoader)null); beanFactory.freezeConfiguration(); beanFactory.preInstantiateSingletons(); }
接口:
void preInstantiateSingletons() throws BeansException;
public void preInstantiateSingletons() throws BeansException { if (this.logger.isTraceEnabled()) { this.logger.trace("Pre-instantiating singletons in " + this); } List<String> beanNames = new ArrayList(this.beanDefinitionNames); Iterator var2 = beanNames.iterator();//取出名字 while(true) { String beanName; Object bean; do { while(true) { RootBeanDefinition bd; do { do { do { if (!var2.hasNext()) { var2 = beanNames.iterator(); while(var2.hasNext()) { beanName = (String)var2.next(); Object singletonInstance = this.getSingleton(beanName); if (singletonInstance instanceof SmartInitializingSingleton) { SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton)singletonInstance; if (System.getSecurityManager() != null) { AccessController.doPrivileged(() -> { smartSingleton.afterSingletonsInstantiated(); return null; }, this.getAccessControlContext()); } else { smartSingleton.afterSingletonsInstantiated(); } } } return; } beanName = (String)var2.next(); bd = this.getMergedLocalBeanDefinition(beanName); } while(bd.isAbstract());//單例抽象懶加載 } while(!bd.isSingleton()); } while(bd.isLazyInit()); if (this.isFactoryBean(beanName)) { bean = this.getBean("&" + beanName); break; } this.getBean(beanName); } } while(!(bean instanceof FactoryBean)); FactoryBean<?> factory = (FactoryBean)bean; boolean isEagerInit; if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { SmartFactoryBean var10000 = (SmartFactoryBean)factory; ((SmartFactoryBean)factory).getClass(); isEagerInit = (Boolean)AccessController.doPrivileged(var10000::isEagerInit, this.getAccessControlContext()); } else { isEagerInit = factory instanceof SmartFactoryBean && ((SmartFactoryBean)factory).isEagerInit(); } if (isEagerInit) { this.getBean(beanName); } } }
getSingleton方法:
@Nullable protected Object getSingleton(String beanName, boolean allowEarlyReference) { Object singletonObject = this.singletonObjects.get(beanName);// if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) { 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; }
3、怎么避免循環依賴?
三級緩存
- 一級緩存:singletonObjects,存放完全實例化屬性賦值完成的Bean,直接可以使用。
- 二級緩存:earlySingletonObjects,存放早期Bean的引用,尚未屬性裝配的Bean
- 三級緩存:singletonFactories,三級緩存,存放實例化完成的Bean工廠。
假設A依賴B,B依賴A(注意:這里是set屬性依賴)分以下步驟執行:
A依次執行doGetBean、查詢緩存、createBean創建實例,實例化完成放入三級緩存singletonFactories中,接着執行populateBean方法裝配屬性,但是發現有一個屬性是B的對象。因此再次調用doGetBean方法創建B的實例,依次執行doGetBean、查詢緩存、createBean創建實例,實例化完成之后放入三級緩存singletonFactories中,執行populateBean裝配屬性,但是此時發現有一個屬性是A對象。
因此再次調用doGetBean創建A的實例,但是執行到getSingleton查詢緩存的時候,從三級緩存中查詢到了A的實例(早期引用,未完成屬性裝配),此時直接返回A,不用執行后續的流程創建A了,那么B就完成了屬性裝配,此時是一個完整的對象放入到一級緩存singletonObjects中。
B創建完成了,則A自然完成了屬性裝配,也創建完成放入了一級緩存singletonObjects中。