spring 5.0.21.BUILD-SNAPSHOT原始碼解讀,第二集(Spring迴圈依賴解決方案)
1.老辦法,程式碼放在碼雲:
https://gitee.com/rich_lz/spring_kz所屬分支:springReferDepends;
2.迴圈依賴程式碼演示:
@Repository public class TestDao {
/**
*
*dao層依賴TestService
*/
@Autowired private TestService testservice; public String sayHello(String name){ System.out.println("介面呼叫==>"+name);return name; } }
@Service(value = "TestService") public class TestService {
/**
*TestService 又依賴TestDao
*
**/
@Autowired private TestDao testDao; @Autowired TestService(TestDao testDao){ this.testDao = testDao; } public String test(String name){return testDao.sayHello(name); } }
3.程式碼除錯:
通過第一集的內容,我們大概瞭解到spring先要載入bean,然後再例項化,那麼我們很容易就想到發生迴圈依賴肯定是在例項化的過程中,那麼我們就很容易的找到我們需要除錯的地方了,AbstractApplicationContext.refresh()
這個方法中一共有11個方法,真正例項化bean的地方是在finishBeanFactoryInitialization(beanFactory); 內,通過原始碼跟蹤定位到DefaultListableBeanFactory.preInstantiateSingletons()。
@Override public void preInstantiateSingletons() throws BeansException { if (logger.isDebugEnabled()) { logger.debug("Pre-instantiating singletons in " + this); } // 獲取到所有已經定義好,並且放到list集合中的bean. List<String> beanNames = new ArrayList<>(this.beanDefinitionNames); // Trigger initialization of all non-lazy singleton beans... for (String beanName : beanNames) { RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// 這個bean不是抽象的,是單例,不是懶載入。 if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { if (isFactoryBean(beanName)) { Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
//實現FactoryBean介面的bean. if (bean instanceof FactoryBean) { FactoryBean<?> factory = (FactoryBean<?>) bean; boolean isEagerInit; if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { isEagerInit = AccessController.doPrivileged( (PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit, getAccessControlContext()); } else { isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean<?>) factory).isEagerInit()); } if (isEagerInit) { getBean(beanName); } } } else {
//核心方法,普通定義的bean。 getBean(beanName); } } } // Trigger post-initialization callback for all applicable beans... for (String beanName : beanNames) { Object singletonInstance = getSingleton(beanName); if (singletonInstance instanceof SmartInitializingSingleton) { SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance; if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { smartSingleton.afterSingletonsInstantiated(); return null; }, getAccessControlContext()); } else { smartSingleton.afterSingletonsInstantiated(); } } } }
4.再開啟getBean方法再往下跟會發現呼叫的事AbstractBeanFactory.doGetBean()方法:
/** * 開始例項化bean. */ // Create bean instance. if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { try {
//回撥,會呼叫AbstractAutowireCapableBeanFactory的createBean方法。 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; } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }
5.接著再次進入到createBean方法中.
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { Class<?> resolvedClass = resolveBeanClass(mbd, beanName); if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) { mbdToUse = new RootBeanDefinition(mbd); mbdToUse.setBeanClass(resolvedClass); } ............
try {//開始建立bean Object beanInstance = doCreateBean(beanName, mbdToUse, args); if (logger.isDebugEnabled()) { logger.debug("Finished creating instance of bean '" + beanName + "'"); } return beanInstance; } catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) { // A previously detected exception with proper bean creation context already, // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry. throw ex; } }
6.又進入到doCreateBean方法(這個方法很重要):
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { // Instantiate the bean. BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { //第1步,例項化物件,根據建構函式例項化物件。 instanceWrapper = createBeanInstance(beanName, mbd, args); } Object bean = instanceWrapper.getWrappedInstance(); Class<?> beanType = instanceWrapper.getWrappedClass(); if (beanType != NullBean.class) { mbd.resolvedTargetType = beanType; } // Allow post-processors to modify the merged bean definition. synchronized (mbd.postProcessingLock) { if (!mbd.postProcessed) { try { applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); } catch (Throwable ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", ex); } mbd.postProcessed = true; } } /** * 根據是否是單例,是否允許迴圈依賴,當前物件是否在建立 三個條件。 * 目的是將已經例項化的物件(還沒有初始化)放入到一個對外可識別的容器中。 */ // Eagerly cache singletons to be able to resolve circular references // even when triggered by lifecycle interfaces like BeanFactoryAware. boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (logger.isDebugEnabled()) { logger.debug("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } /** * 將已經例項化的物件放入到singletonFactories,registeredSingletons 中。 */ addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } // Initialize the bean instance. Object exposedObject = bean; try { //第二步,填充屬性,解決依賴問題。 populateBean(beanName, mbd, instanceWrapper); //呼叫initmethod方法,初始化。 exposedObject = initializeBean(beanName, exposedObject, mbd); } catch (Throwable ex) { if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) { throw (BeanCreationException) ex; } else { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex); } } if (earlySingletonExposure) { Object earlySingletonReference = getSingleton(beanName, false); if (earlySingletonReference != null) { if (exposedObject == bean) { exposedObject = earlySingletonReference; } else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { String[] dependentBeans = getDependentBeans(beanName); Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length); for (String dependentBean : dependentBeans) { if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { actualDependentBeans.add(dependentBean); } } if (!actualDependentBeans.isEmpty()) { throw new BeanCurrentlyInCreationException(beanName, "Bean with name '" + beanName + "' has been injected into other beans [" + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + "] in its raw version as part of a circular reference, but has eventually been " + "wrapped. This means that said other beans do not use the final version of the " + "bean. This is often the result of over-eager type matching - consider using " + "'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example."); } } } } // Register bean as disposable. try { registerDisposableBeanIfNecessary(beanName, bean, mbd); } catch (BeanDefinitionValidationException ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); } return exposedObject; }
7.上述程式碼中有幾個方法很重要:createBeanInstance,建立例項物件,就是呼叫建構函式,程式碼如下:
return BeanUtils.instantiateClass(constructorToUse);
初始化物件完畢之後,只是在記憶體中分配了一塊空地兒,物件中的屬性全部都是null。
8.那麼接下來就需要進入到populateBean填充屬性的方法中了,注意在填充屬性之前,例項化之後,會做一個操作,將剛才例項化的TestDao(半成品只有記憶體空間,沒有屬性值)放到三級快取中:
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); } } }
9.這個時候才會填充剛才已經例項化好的Testdao物件,進入到populateBean方法中,主要程式碼如下:
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) { //獲取bean的後置處理器,對已經例項化的bean做處理。if (hasInstAwareBpps) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { /** * AutowiredAnnotationBeanPostProcessor 後置處理器處理屬性依賴。 */ InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); if (pvs == null) { return; } } } }
10.這個時候再次進入到postProcessPropertyValues 方法中發現進入到InjectionMetadata的inject方法中,我們不妨先看看呼叫這個方法之前傳入的引數:
11.引數中的bean中的屬性testservice依然為null,說明此時還沒有注入,那麼我們除錯再進入到inject中,進入到這個方法中:
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable { Collection<InjectedElement> checkedElements = this.checkedElements; Collection<InjectedElement> elementsToIterate = (checkedElements != null ? checkedElements : this.injectedElements);
//獲取到這個物件的所填充屬性。 if (!elementsToIterate.isEmpty()) { for (InjectedElement element : elementsToIterate) { if (logger.isDebugEnabled()) { logger.debug("Processing injected element of bean '" + beanName + "': " + element); } element.inject(target, beanName, pvs); } } }
12. 通過上述接入可以看到TestDao 已經例項化,現在已經獲取到他的一個屬性型別為Testservice.
再次接著走入到element.inject(target, beanName, pvs)方法中:
@Override @Nullable public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException { ........else { Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary( descriptor, requestingBeanName); if (result == null) {//開始處理依賴 result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter); } return result; } }
13.需要再次的進入到:doResolveDependency中:
@Nullable public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException { //開始處理依賴,處理基本型別,像Array,Map,Collection, Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter); if (multipleBeans != null) { return multipleBeans; } //根據屬性匹配看有沒有匹配的bean. Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor); if (matchingBeans.isEmpty()) { if (isRequired(descriptor)) { raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor); } return null; } String autowiredBeanName; Object instanceCandidate; if (matchingBeans.size() > 1) { autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor); if (autowiredBeanName == null) { if (isRequired(descriptor) || !indicatesMultipleBeans(type)) { return descriptor.resolveNotUnique(type, matchingBeans); } else { // In case of an optional Collection/Map, silently ignore a non-unique case: // possibly it was meant to be an empty collection of multiple regular beans // (before 4.3 in particular when we didn't even look for collection beans). return null; } } instanceCandidate = matchingBeans.get(autowiredBeanName); } else { // We have exactly one match. Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next(); autowiredBeanName = entry.getKey(); instanceCandidate = entry.getValue(); } if (autowiredBeanNames != null) { autowiredBeanNames.add(autowiredBeanName); } if (instanceCandidate instanceof Class) { //根據型別尋找daoBean定義之後,開始例項化這個bean. instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this); } Object result = instanceCandidate; if (result instanceof NullBean) { if (isRequired(descriptor)) { raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor); } result = null; } if (!ClassUtils.isAssignableValue(type, result)) { throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass()); } return result; } finally { ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint); } }
14.我們注意到findAutowireCandidates 這個方法好像是跟註解有關係的,先通過表示式看下結果:
15.通過返回結果值看到時一個TestService 的class類,很明顯這個方法是根據我傳入的引數名稱,從bean定義的容器中返回一個class物件,除錯進去:
protected Map<String, Object> findAutowireCandidates( @Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
//這裡根據傳入的beanName = TestDao, requireType =com.audaque.learn.srvice.TestService
//直接找到TestService這個bean.
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this, requiredType, true, descriptor.isEager()); Map<String, Object> result = new LinkedHashMap<>(candidateNames.length); for (String candidate : candidateNames) { if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) { addCandidateEntry(result, candidate, descriptor, requiredType); } } if (result.isEmpty() && !indicatesMultipleBeans(requiredType)) { // Consider fallback matches if the first pass failed to find anything... DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch(); for (String candidate : candidateNames) { if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor)) { addCandidateEntry(result, candidate, descriptor, requiredType); } } if (result.isEmpty()) { // Consider self references as a final pass... // but in the case of a dependency collection, not the very same bean itself. for (String candidate : candidateNames) { if (isSelfReference(beanName, candidate) && (!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) && isAutowireCandidate(candidate, fallbackDescriptor)) { addCandidateEntry(result, candidate, descriptor, requiredType); } } } } return result; }
16.這個方法主要程式碼就是第一行的
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());從bean定義的容器中獲取指定型別的bean.
17.通過看引數返回值,發現已經返回了我們需要的testSerivce的定義物件,其實這裡就是這個testService的beandefinition.
那麼接下來已經獲取到屬性對應的bean定義資訊了,那麼就需要去例項化這個屬性的bean了,程式碼會跳轉到descriptor.resolveCandidate這個方法中,
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory) throws BeansException { //別看只有一行程式碼,要了我的命,在這裡再去例項化Testservice,流程跟例項化Testdao一樣。 return beanFactory.getBean(beanName); }
18.在通過一圈的除錯,截圖發現神奇的問題:
先市例項化TestDao依賴TestService,那麼會去例項化TestService,但是TestService中又依賴TestDao 的屬性,但是現在截圖中的效果是,TestService中的TestDao有值,但是TestDao中的屬性值依然為空,說明在testservice例項化中已經從我們上邊的某個地方獲取到了TestDao,哈哈哈,是不是很神奇,寫了半天了,才到了見證奇蹟的時候了,其實我在第八步驟的時候,就有埋下伏筆的,在例項化TestDao 的時候,已經提前將這個半成品暴露出去了,那麼在例項化Testservice的TestDao中獲取,會從這個把這個半成品放到TestService 的testdao 屬性上,不信?,程式碼如下:
protected Object getSingleton(String beanName, boolean allowEarlyReference) { Object singletonObject = this.singletonObjects.get(beanName);
//判斷這個bean是否正在建立。 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); this.singletonFactories.remove(beanName); } } } } return singletonObject; }
再結合第8步,是不是瞬間明白了?哈哈哈,不過沒明白也沒關係,我再來重新梳理一遍。
TestService依賴TestDao ,TestDao依賴TestService.
1.例項化TestDao,會呼叫getSingleton(),此時第一次呼叫返回空,那麼就去例項化,並把返回結果TestDao放到三級快取中,也就是singletonFactories中,並標註這個testDao的bean正在建立。
2.再去填充屬性,發現有一個型別為TestService的屬性,那麼就會去例項化TestService這個物件。
3.例項化TestService這個物件,同樣呼叫getSingleton()返回空,那麼也要去例項化一個TestService物件,並把它放到singletonFactories三級快取。
4.再去尋找TestService依賴的Testdao,這個時候呼叫getSingleton(),由於在第一步驟的時候已經放到快取中,並且當前的屬性testDao是在建立中,所有getSingleton()方法就會把第一部建立的物件返回。
5.TestService的屬性填充完了。
6.開始再次返回到TestDao中將TestService設定到它本身的屬性中。至此迴圈依賴就解決掉了。
*:通過這個分析其實並不是所有的迴圈依賴都能解決,我通過上述的過程分析可以看出來,屬性之間的依賴是可以解決,建構函式與屬性之間的依賴也是可以解決的,建構函式與建構函式之間的依賴是解決不了的。