spring源碼解析-循環(huán)依賴

講解內(nèi)容:

  • spring的循環(huán)依賴---屬性注入--自動(dòng)注入
  • spring bean的生命周期
  • spring bean實(shí)例化的過程
  • spring循環(huán)依賴

講解模式

  • 打斷點(diǎn),一步一步走過spring bean循環(huán)依賴解決過程茬腿。由于spring 創(chuàng)建bean過程繁雜智厌,重要的代碼會(huì)講解蝇棉,不重要的忽略谚殊。自動(dòng)注入也是個(gè)重點(diǎn)婉陷,后面文章會(huì)再次講解到恬砂。
  • 本筆記是個(gè)人學(xué)習(xí)子路老師的課程所做的咧纠,有興趣的可以去看看他的課,講的更好

帶著問題學(xué)習(xí)

問題1:spring當(dāng)中的循環(huán)依賴如何解決的
問題2:spring當(dāng)中怎么支持循環(huán)依賴的
回答:
spring中的AbstractAutowireBeanFactory類里面有個(gè)變量allowCircularRefrence=true這是設(shè)置是否支持循環(huán)依賴的參數(shù)泻骤,在么個(gè)bean創(chuàng)建的過程中晤柄,都會(huì)進(jìn)行判斷厌衔。可以通過啟動(dòng)類中的

public static void main(String[] args) {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
        AbstractAutowireCapableBeanFactory acb = ac.getDefaultListableBeanFactory();
        acb.setAllowCircularReferences(false);
        ac.register(Test.class);
        ac.refresh();
        ac.getBean(IndexService.class).getService();
    }

或者修改源碼,在AnnotationConfigApplicationContext類中直接

public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
        this();
        setAllowCircularReference(false);
        register(annotatedClasses);
        refresh();
    }

問題3:如何證明spring默認(rèn)支持循環(huán)依賴(源碼細(xì)節(jié))
問題4:對(duì)spring源碼有什么了解嗎售担?(可以回答一個(gè)IOC或者AOP即可)
問題5:對(duì)spring源碼深入研究,可以進(jìn)行二次擴(kuò)展嗎氢伟?(直接繼承BeanFactoryPostProcess類)

public class ZbBeanFactoryPostProcess implements BeanFactoryPostProcessor {
    //這里的factory中調(diào)用的所有對(duì)象都是二級(jí)緩存中的酷宵,在加載到三級(jí)緩存中之前會(huì)調(diào)用用戶自己寫的擴(kuò)展類。
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
//      GenericBeanDefinition是BeanDefinition的子類器虾,子類具有更多的實(shí)現(xiàn)讯嫂,rootBeanDefinition也是BeanDefinition的子類
        GenericBeanDefinition  userService = (GenericBeanDefinition)configurableListableBeanFactory.getBeanDefinition("userService");
        userService.setScope("");
        userService.setBeanClassName("XXX");
    }
}

問題6:如何關(guān)閉單例循環(huán)依賴
啟動(dòng)類中AnnotationConfigApplicationContext.java的構(gòu)造方法中添加setAllowCircularReference(false即可)

public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
    this();
    setAllowCircularReference(false);
    register(annotatedClasses);
    refresh();
}

問題7:@Autowired和@Source有什么不一樣
回答:在bea初始化的時(shí)候bean注入各種屬性的時(shí)候,處理他們的后置處理器不一樣
問題:如何解決循環(huán)依賴>>>依賴注入功能>>>初始化完成依賴注入>{
1兆沙、初始化bean ------ b
}

問題:循環(huán)依賴的過程
回答:
getBean() ------index object --------注入U(xiǎn)serService-----getBean(UserService) ---從容器中拿(三級(jí)緩存)-----拿不到----判斷是否需要第三個(gè)緩存中拿------開始new Userservice-----object UserService --------注入index----從容器中拿getBean(Index)-----index不等于nulll,注入半成品index---創(chuàng)建userservice .

問題:spring bean聲明周期如何完成依賴注入的呢欧芽?

問題:spring bean的產(chǎn)生過程,bean是如何產(chǎn)生的

現(xiàn)有class--beanDefinition(類)------object(bean)

spring懶加載葛圃,在類上面直接使用注解@Lazy(true)千扔,表明這個(gè)類在初始化的時(shí)候不加載,到用到的時(shí)候才會(huì)去加載

注意:
bean----------spring bean
java對(duì)象-----對(duì)象

spring bean創(chuàng)建過程簡(jiǎn)單概述

先過過眼装悲,具體內(nèi)容后面詳細(xì)講解昏鹃,這里有個(gè)大概印象
getBean() ------index object --------注入U(xiǎn)serService-----getBean(UserService) ---從容器中拿(三級(jí)緩存)-----拿不到----判斷是否需要第三個(gè)緩存中拿------開始new Userservice-----object UserService --------注入index----從容器中拿getBean(Index)-----index不等于nulll,注入半成品index---創(chuàng)建userservice .

文字描述

  • 實(shí)例化一個(gè)ApplicationContext的對(duì)象;
  • 調(diào)用bean工廠后置處理器完成掃描诀诊;
  • 循環(huán)解析掃描出來(lái)的類信息洞渤;
  • 實(shí)例化一個(gè)BeanDefinition對(duì)象來(lái)存儲(chǔ)解析出來(lái)的信息;
  • 把實(shí)例化好的beanDefinition對(duì)象put到beanDefinitionMap當(dāng)中緩存起來(lái)属瓣,以便后面實(shí)例化bean载迄;
  • 再次調(diào)用bean工廠后置處理器;
  • 當(dāng)然spring還會(huì)干很多事情抡蛙,比如國(guó)際化护昧,比如注冊(cè)BeanPostProcessor等等,如果我們只關(guān)心如何實(shí)例化一個(gè)bean的話那么這一步就是spring調(diào)用finishBeanFactoryInitialization方法來(lái)實(shí)例化單例的bean粗截,實(shí)例化之前spring要做驗(yàn)證惋耙,需要遍歷所有掃描出來(lái)的類,依次判斷這個(gè)bean是否Lazy,是否prototype绽榛,是否abstract等等湿酸;
  • 如果驗(yàn)證完成spring在實(shí)例化一個(gè)bean之前需要推斷構(gòu)造方法,因?yàn)閟pring實(shí)例化對(duì)象是通過構(gòu)造方法反射灭美,故而需要知道用哪個(gè)構(gòu)造方法推溃;
  • 推斷完構(gòu)造方法之后spring調(diào)用構(gòu)造方法反射實(shí)例化一個(gè)對(duì)象;注意我這里說(shuō)的是對(duì)象届腐、對(duì)象铁坎、對(duì)象;這個(gè)時(shí)候?qū)ο笠呀?jīng)實(shí)例化出來(lái)了犁苏,但是并不是一個(gè)完整的bean硬萍,最簡(jiǎn)單的體現(xiàn)是這個(gè)時(shí)候?qū)嵗鰜?lái)的對(duì)象屬性是沒有注入,所以不是一個(gè)完整的bean傀顾;
  • spring處理合并后的beanDefinition(合并襟铭?是spring當(dāng)中非常重要的一塊內(nèi)容,后面的文章我會(huì)分析)短曾;
  • 判斷是否支持循環(huán)依賴寒砖,如果支持則提前把一個(gè)工廠存入singletonFactories——map;
  • 判斷是否需要完成屬性注入
  • 如果需要完成屬性注入嫉拐,則開始注入屬性
  • 判斷bean的類型回調(diào)Aware接口
  • 調(diào)用生命周期回調(diào)方法
  • 如果需要代理則完成代理
  • put到單例池——bean完成——存在spring容器當(dāng)中

對(duì)象的創(chuàng)建過程

1哩都、scan掃描類
2、parse解析婉徘,利用for循環(huán)對(duì)所有遍歷的類進(jìn)行解析,設(shè)置類的名稱漠嵌,父類,單例還是原型等等盖呼。

for (){
    GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
    genericBeanDefinition.setBeanClassName("XXX");
    genericBeanDefinition.setBeanClass("XXXX.class");
    genericBeanDefinition.setScope("prototytype"
    .......
    //放入到一級(jí)緩存中
    map.put("XXXX");
    list<String>.add(xxxx)
}

3儒鹿、調(diào)用擴(kuò)展,
遍歷map validate校驗(yàn)類中是否符合各種規(guī)則
然后符合就直接new了几晤。

開啟spring循環(huán)依賴講解

循環(huán)依賴樣例

UserService.java

package test.service;/**
 * Created by zhanbei on 2020/12/6.
 */
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class UserService {
    @Autowired
    private IndexService indexService;

    public UserService(){
        System.out.println("UserService start");
    }

}

IndexService.java

package test.service;/**
 * Created by zhanbei on 2020/12/6.
 */

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class IndexService {

    @Autowired
    private UserService userService;

    public IndexService(){
        System.out.println("IndexServicde started");
    }
    public String getService(){
        return "IndexService";
    }
}

bean的實(shí)例化生命周期

1约炎、啟動(dòng)類中調(diào)用的AnnotationConfigApplicationContext類

@Lazy(true)
public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Test.class);
        ac.getBean(IndexService.class).getService();
    }
}

在這里可以做很多事情,可以關(guān)閉循環(huán)依賴等等蟹瘾,只要在ac.refresh()方法執(zhí)行之前圾浅,可以修改很多spring內(nèi)部的東西。如下

    public static void main(String[] args) {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
        AbstractAutowireCapableBeanFactory acb = ac.getDefaultListableBeanFactory();
        //可以在這里關(guān)閉循環(huán)依賴
        acb.setAllowCircularReferences(false);
        ac.register(Test.class);
        ac.refresh();
        ac.getBean(IndexService.class).getService();
    }

2憾朴、AnnotationConfigApplicationContext類中主要代碼狸捕,主要構(gòu)件bean生命周期的是refresh()方法

public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
    this();
        //也可以在這關(guān)閉循環(huán)依賴,這里是我個(gè)人手動(dòng)修改的spring源碼
    setAllowCircularReference(false);
    register(annotatedClasses);
    refresh();
}

3众雷、refresh方法里才是整個(gè)bean生命周期開始的地方灸拍,準(zhǔn)確的開始地方做祝,后面會(huì)講解(refresh在spring-context-5.1.13.RELEASE.jar.org.springframework.context.support.AbstractApplicationContext.class中)

@Override
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // Prepare this context for refreshing.
        prepareRefresh();
        // Tell the subclass to refresh the internal bean factory.
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        // Prepare the bean factory for use in this context.
        prepareBeanFactory(beanFactory);
        try {
            // Allows post-processing of the bean factory in context subclasses.
            postProcessBeanFactory(beanFactory);
            // Invoke factory processors registered as beans in the context.
            invokeBeanFactoryPostProcessors(beanFactory);
            // Register bean processors that intercept bean creation.
            registerBeanPostProcessors(beanFactory);
            // Initialize message source for this context.
            initMessageSource();
            // Initialize event multicaster for this context.
            initApplicationEventMulticaster();
            // Initialize other special beans in specific context subclasses.
            onRefresh();
            // Check for listener beans and register them.
            registerListeners();
            // Instantiate all remaining (non-lazy-init) singletons.
            //調(diào)用finishBeanFactoryInitialization方法實(shí)例化所有掃描出來(lái)的類
            //spring在AbstractApplicationContext#finishBeanFactoryInitialization方法中完成了bean的實(shí)例化。這點(diǎn)需要記住
            finishBeanFactoryInitialization(beanFactory);
            // Last step: publish corresponding event.
            finishRefresh();
        }
        catch (BeansException ex) {
            if (logger.isWarnEnabled()) {
                logger.warn("Exception encountered during context initialization - " +
                        "cancelling refresh attempt: " + ex);
            }
            // Destroy already created singletons to avoid dangling resources.
            destroyBeans();
            // Reset 'active' flag.
            cancelRefresh(ex);
            // Propagate exception to caller.
            throw ex;
        }
        finally {
            // Reset common introspection caches in Spring's core, since we
            // might not ever need metadata for singleton beans anymore...
            resetCommonCaches();
        }
    }
}

3.1株搔、finishBeanFactoryInitialization方法中調(diào)用preInstantiateSingletons初始化掃描出來(lái)的類剖淀。

**
* Finish the initialization of this context's bean factory,
* initializing all remaining singleton beans.
*/
rotected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    // Initialize conversion service for this context.
    if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
            beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
        beanFactory.setConversionService(
                beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
    }
    // Register a default embedded value resolver if no bean post-processor
    // (such as a PropertyPlaceholderConfigurer bean) registered any before:
    // at this point, primarily for resolution in annotation attribute values.
    if (!beanFactory.hasEmbeddedValueResolver()) {
        beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
    }
    // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
    String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
    for (String weaverAwareName : weaverAwareNames) {
        getBean(weaverAwareName);
    }
    // Stop using the temporary ClassLoader for type matching.
    beanFactory.setTempClassLoader(null);
    // Allow for caching all bean definition metadata, not expecting further changes.
    beanFactory.freezeConfiguration();
    // Instantiate all remaining (non-lazy-init) singletons.
    beanFactory.preInstantiateSingletons(); 
}

3.2、preInstantiateSingletons方法會(huì)經(jīng)過一系列的判斷之后纤房,調(diào)用getBean方法區(qū)實(shí)例化掃描出來(lái)的類
preInstantiateSingletons位于(spring-beans-5.1.13.RELEASE.jar.org.springframework.beans.factory.support.DefaultListableBeanFactory.class)

@Override
public void preInstantiateSingletons() throws BeansException {
    if (logger.isDebugEnabled()) {
        logger.debug("Pre-instantiating singletons in " + this);
    }
    // Iterate over a copy to allow for init methods which in turn register new bean definitions.
    // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
    List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
    // Trigger initialization of all non-lazy singleton beans...
    for (String beanName : beanNames) {
        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
            if (isFactoryBean(beanName)) {
                Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                if (bean instanceof FactoryBean) {
                    final 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 {
                getBean(beanName);
            }
        }
    }
    // Trigger post-initialization callback for all applicable beans...
    for (String beanName : beanNames) {
        Object singletonInstance = getSingleton(beanName);
        if (singletonInstance instanceof SmartInitializingSingleton) {
            final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
            if (System.getSecurityManager() != null) {
                AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                    smartSingleton.afterSingletonsInstantiated();
                    return null;
                }, getAccessControlContext());
            }
            else {
                smartSingleton.afterSingletonsInstantiated();
            }
        }
    }
}

3.3、getBean僅為一個(gè)空殼翻诉,調(diào)用了doGetBean方法(代碼較長(zhǎng)炮姨,大致過一樣即可,下面會(huì)繼續(xù)針對(duì)這個(gè)有詳細(xì)講解)

public AbstractBeanFactory() {
}
public AbstractBeanFactory(@Nullable BeanFactory parentBeanFactory) {
    this.parentBeanFactory = parentBeanFactory;
}
public Object getBean(String name) throws BeansException {
    return this.doGetBean(name, (Class)null, (Object[])null, false);
}
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
    return this.doGetBean(name, requiredType, (Object[])null, false);
}
public Object getBean(String name, Object... args) throws BeansException {
    return this.doGetBean(name, (Class)null, args, false);
}
public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args) throws BeansException {
    return this.doGetBean(name, requiredType, args, false);
}
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly
    String beanName = this.transformedBeanName(name);
    Object sharedInstance = this.getSingleton(beanName);
    Object bean;
    if(sharedInstance != null && args == null) {
        if(this.logger.isTraceEnabled()) {
            if(this.isSingletonCurrentlyInCreation(beanName)) {
                this.logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not 
            } else {
                this.logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
            }
        }
        bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
    } else {
        if(this.isPrototypeCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }
        BeanFactory parentBeanFactory = this.getParentBeanFactory();
        if(parentBeanFactory != null && !this.containsBeanDefinition(beanName)) {
            String nameToLookup = this.originalBeanName(name);
            if(parentBeanFactory instanceof AbstractBeanFactory) {
                return ((AbstractBeanFactory)parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckO
            }
            if(args != null) {
                return parentBeanFactory.getBean(nameToLookup, args);
            }
            if(requiredType != null) {
                return parentBeanFactory.getBean(nameToLookup, requiredType);
            }
            return parentBeanFactory.getBean(nameToLookup);
        }
        if(!typeCheckOnly) {
            this.markBeanAsCreated(beanName);
        }
        try {
            RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
            this.checkMergedBeanDefinition(mbd, beanName, args);
            String[] dependsOn = mbd.getDependsOn();
            String[] var11;
            if(dependsOn != null) {
                var11 = dependsOn;
                int var12 = dependsOn.length;
                for(int var13 = 0; var13 < var12; ++var13) {
                    String dep = var11[var13];
                    if(this.isDependent(beanName, dep)) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on r
                    }
                    this.registerDependentBean(dep, beanName);
                    try {
                        this.getBean(dep);
                    } catch (NoSuchBeanDefinitionException var24) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' de
                    }
                }
            }
            if(mbd.isSingleton()) {
                sharedInstance = this.getSingleton(beanName, () -> {
                    try {
                        return this.createBean(beanName, mbd, args);
                    } catch (BeansException var5) {
                        this.destroySingleton(beanName);
                        throw var5;
                    }
                });
                bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            } else if(mbd.isPrototype()) {
                var11 = null;
                Object prototypeInstance;
                try {
                    this.beforePrototypeCreation(beanName);
                    prototypeInstance = this.createBean(beanName, mbd, args);
                } finally {
                    this.afterPrototypeCreation(beanName);
                }
                bean = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            } else {
                String scopeName = mbd.getScope();
                Scope scope = (Scope)this.scopes.get(scopeName);
                if(scope == null) {
                    throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                }
                try {
                    Object scopedInstance = scope.get(beanName, () -> {
                        this.beforePrototypeCreation(beanName);
                        Object var4;
                        try {
                            var4 = this.createBean(beanName, mbd, args);
                        } finally {
                            this.afterPrototypeCreation(beanName);
                        }
                        return var4;
                    });
                    bean = this.getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                } catch (IllegalStateException var23) {
                    throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current
                }
            }
        } catch (BeansException var26) {
            this.cleanupAfterBeanCreationFailure(beanName);
            throw var26;
        }
    }
    if(requiredType != null && !requiredType.isInstance(bean)) {
        try {
            T convertedBean = this.getTypeConverter().convertIfNecessary(bean, requiredType);
            if(convertedBean == null) {
                throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
            } else {
                return convertedBean;
            }
        } catch (TypeMismatchException var25) {
            if(this.logger.isTraceEnabled()) {
                this.logger.trace("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualified
            }
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
        }
    } else {
        return bean;
    }
}

3.4碰煌、refresh()方法中在經(jīng)過一堆的校驗(yàn)之后舒岸,開始調(diào)用createBean創(chuàng)建bean
()createBean位于org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java)

/**
     * Central method of this class: creates a bean instance,
     * populates the bean instance, applies post-processors, etc.
     * @see #doCreateBean
     */
    @Override
    protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
            throws BeanCreationException {

        if (logger.isDebugEnabled()) {
            logger.debug("Creating instance of bean '" + beanName + "'");
        }
        RootBeanDefinition mbdToUse = mbd;

        // Make sure bean class is actually resolved at this point, and
        // clone the bean definition in case of a dynamically resolved Class
        // which cannot be stored in the shared merged bean definition.
        Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            mbdToUse = new RootBeanDefinition(mbd);
            mbdToUse.setBeanClass(resolvedClass);
        }

        // Prepare method overrides.
        try {
            mbdToUse.prepareMethodOverrides();
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
                    beanName, "Validation of method overrides failed", ex);
        }

        try {
            // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
            Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
            if (bean != null) {
                return bean;
            }
        }
        catch (Throwable ex) {
            throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
                    "BeanPostProcessor before instantiation of bean failed", ex);
        }

        try {
            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;
        }
        catch (Throwable ex) {
            throw new BeanCreationException(
                    mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
        }
    }

doGetBean方法內(nèi)容很多,這個(gè)方法非常重要芦圾,不僅僅針對(duì)循環(huán)依賴蛾派。甚至整個(gè)springbean生命周期也有舉足輕重的地位,下面將會(huì)細(xì)致講解

package test.service;
/**
 * Created by zhanbei on 2020/12/6.
 */
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
 * @ClassName UserService
 * @Description TODO
 * @Author zhanbei
 * @Date 2020/12/6 21:41
 * @Version 1.0
 **/
@
        Component
public class UserService {@
        Autowired
private IndexService indexService;
    public UserService() {
        System.out.println("UserService start");
    }
    protected < T > T doGetBean(final String name, @Nullable final Class < T > requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
        //這個(gè)方法非常重要,但是和筆者今天要分析的循環(huán)依賴沒什么很大的關(guān)系//讀者可以簡(jiǎn)單的認(rèn)為就是對(duì)beanName做一個(gè)校驗(yàn)特殊字符串的功能//我會(huì)在下次更新博客的時(shí)候重點(diǎn)討論這個(gè)方法
        //transformedBeanName(name)這里的name就是bean的名字
        final String beanName = transformedBeanName(name);
        //定義了一個(gè)對(duì)象个少,服存將來(lái)返回出來(lái)的bean
        Object bean;
        // Eagerly check singleton cache for manu ally registered singletons./**
        /**注意這是第一次調(diào)用getSingleton方法洪乍,下面spring還會(huì)調(diào)用一次
         * 但是兩次調(diào)用的不是同一個(gè)方法;屬于方法重載

         * 第一次getSingleton(beanName) 也是循環(huán)依賴最重要的方法

         * 關(guān)于getSingleton(beanName) 具體代碼分析可以參考筆者后面的分析
         *于循環(huán)弓|用需要在創(chuàng)建bean的過程中去獲取被引用的那個(gè)類

         *而被弓用的這個(gè)類如果沒有創(chuàng)建,則會(huì)調(diào)用createBean來(lái)創(chuàng)建這個(gè)bean

         *在創(chuàng)建這個(gè)被引用的bean的過程中會(huì)判斷這個(gè)bean的對(duì)象有沒有實(shí)例化

         * bean的對(duì)象?什么意思呢?

         *為了方便閱讀,讀者-定記住兩個(gè)概念; 什么是bean,什么是對(duì)象

         *筆者以為-個(gè)對(duì)象和bean是有區(qū)別的

         *對(duì)象:只要類被實(shí)例化就可以稱為對(duì)象

         * bean:先得是一個(gè)對(duì)象, 然后這個(gè)對(duì)象需要經(jīng)歷一系列的bean生 命周期

         *后把這個(gè)對(duì)象put到單例池才能算一個(gè)bean

         *讀者千萬(wàn)注意,筆者下文中如果寫到bean和寫到對(duì)象不是隨意寫的是和這里的解釋有關(guān)系的;重點(diǎn)-定要注意; -定;一定; 訖就是spring先new-個(gè)對(duì)象,繼而對(duì)這個(gè)對(duì)象進(jìn)行生命周期回調(diào)

         *接著對(duì)這個(gè)對(duì)象進(jìn)行屬性填流夜焦,也是大家說(shuō)的自動(dòng)注入

         *然后在進(jìn)行AOP判斷等等;這一些操作簡(jiǎn)稱---spring生 命周期.

         *所以一個(gè)bean是一個(gè)經(jīng)歷了spring周期的對(duì)象壳澳,和一個(gè)對(duì)象有區(qū)別

         *回到前面說(shuō)的循環(huán)引用,首先spring掃描到一 個(gè) 要被實(shí)例化的類A

         * 于是spring就去創(chuàng)建A; A=new A-a;new A的過程會(huì)調(diào)用getBean("a"));

         *所謂的getBean方法--核心也就是筆者現(xiàn)在寫注釋的這個(gè)getSingleton(beanName)
         *所謂的getBean方法-核心也就是筆者現(xiàn)在寫注釋的這個(gè)getSingleton(beanName)
         *這個(gè)時(shí)候get出來(lái)肯定為空?為什么是空呢?我寫這么多注釋就是為了解釋這個(gè)問題
         *可能有的讀者會(huì)認(rèn)為getBean就是去容器中獲取,所以肯定為空,實(shí)不然接著往下看

         *如果getA等于空; spring就會(huì)實(shí)例化A;也就是上面的new A

         *但是在實(shí)例化A的時(shí)候會(huì)再次調(diào)用一下

         * getSingleton(String beanName, ObjectFactory<?> singletonFactory)*筆者上面說(shuō)過現(xiàn)在寫的注釋給getSingleton(beanName)

         *也即是第- -次調(diào)用getSingleton(beanName)

         *實(shí)例化一共會(huì)調(diào)用兩次getSingleton方法; 但是是重載

         *第二次調(diào)用getSingleton方法的時(shí)候spring會(huì)在一 個(gè)set集合當(dāng)中記錄一 下這個(gè)類正在被創(chuàng)建

         *這個(gè)定要記住, 在調(diào)用完成第一次getSingleton完成之后* spring判讀這個(gè)類沒有創(chuàng)建茫经, 然后調(diào)用第二 次getSingleton

         *在第二次getSingleton里面記錄了一下自己己經(jīng)開始實(shí)例化這個(gè)類*這是循環(huán)依賴做的最牛逼的地方巷波,兩次getSingleton的調(diào)用

         *也是回答面試時(shí)候關(guān)于循環(huán)依賴必須要回答道的地方; .*要說(shuō)明的spring實(shí)例化一 個(gè)對(duì)象底層用的是反射;

         *spring實(shí)例化一個(gè)對(duì)象的過程非常復(fù)雜, 要推斷構(gòu)造方等等;
         *這里筆者先不討論這個(gè)過程,以后有機(jī)會(huì)更新-下

         *讀者可以理解spring直接通過new關(guān)鍵字來(lái)實(shí)例化一個(gè)對(duì)象

         *但是這個(gè)時(shí)候?qū)ο骯僅僅是一 個(gè)對(duì)象,還不是一 個(gè)完整的bean

         *接著讓這個(gè)對(duì)象完成spring的bean的生命周期

         *過程中spring會(huì)判斷容器是否允許循環(huán)弓用卸伞,判斷循環(huán)引用的代碼筆者下面會(huì)分析

         *前面說(shuō)過spring默認(rèn)是支持循環(huán)引|用的, 筆者后面解析這個(gè)判斷的源碼也是spring默認(rèn)支持循環(huán)引|用的證據(jù)

         *如果允許循環(huán)依賴抹镊,spring會(huì)把這 個(gè)對(duì)象(還不是bean)臨時(shí)存起來(lái),放到一個(gè)map當(dāng)中

         *注意這個(gè)map和單例池是兩個(gè)map,在spring源碼中單例池的map叫做singletonObjects

         *而這個(gè)存放臨時(shí)對(duì)象的map叫做singletonFactories

         *當(dāng)然spring還有一個(gè)存放臨時(shí)對(duì)象的map叫做earlySingletonObjects*所以一共是三個(gè)map,有些博客或者書籍人也叫做三級(jí)緩存

         *為什么需要三個(gè)map呢?先來(lái)了解這三個(gè)map到底都緩存了什么

         *第一個(gè)map singletonObjects存放的單例的bean

         *第二個(gè)map singletonFactories存放的臨時(shí)對(duì)象(沒有完整springBean生命周期的對(duì)象)

         *第三個(gè)map earlySingletonObjects存放的臨時(shí)對(duì)象(沒有完整springBean生命周期的對(duì)象)

         *筆者為了讓大家不懵逼這里吧第二個(gè)和第三個(gè)map功能寫成了一模一樣

         *實(shí)第二個(gè)和第三個(gè)map會(huì)有不一樣的地方,但這里不方便展開講荤傲,下文分析*讀者姑且認(rèn)為這兩個(gè)map是一樣的

         *第一個(gè)map主要為了直接緩存創(chuàng)建好的bean;方便程員去getBean;很好理解*第二個(gè)和第三個(gè)主要為了循環(huán)引用;為什么為了方便循環(huán)引用垮耳,接著往下看

         *把對(duì)象a緩存到第二個(gè)map之后, 會(huì)接著完善生命周期;

         *當(dāng)然spring bean的生命周期很有很多步驟;本文先懷詳細(xì)討論;

         *后面的博客者再更新;

         *當(dāng)進(jìn)行到對(duì)象a的屬性填充的這一周期的時(shí)候弃酌,發(fā)覺a依賴了一個(gè)B類

         *所以spring就會(huì)去判斷這個(gè)B類到底有沒有bean在容器當(dāng)中

         *這里的判斷就是從第一個(gè)map即單例池當(dāng)中去拿一 個(gè)bean

         *后面我會(huì)通過源碼來(lái)證明是從第-個(gè)map中拿一個(gè)bean的

         *假設(shè)沒有氨菇,那么spring會(huì)先去調(diào)用createBean創(chuàng)建這 個(gè)bean

         *于是又回到和創(chuàng)建A-樣的流程,在創(chuàng)建B的時(shí)候同樣也會(huì)去getBean("B");* getBean核心也就是筆者現(xiàn)在寫注釋的這個(gè)getSingleton(beanName)方法
         *下面我重申一下:因?yàn)槭侵攸c(diǎn)

         *這個(gè)時(shí)候get出來(lái)肯定為空?為什么是空呢?我寫這么多注釋就是為了解釋這個(gè)問題?
         *可能有的讀者會(huì)認(rèn)為qetBean就是去容器中獲取:

         *可能有的讀者會(huì)認(rèn)為getBean就是去容器中獲取;

         *所以肯定為空妓湘,期不然查蓉,接著往下看; .

         *第一 -次調(diào)用完getSingleton完成之后會(huì)調(diào)用第二次getSingleton

         *第二次調(diào)用getSingleton同樣會(huì)在set集合當(dāng)中去記錄B正在被創(chuàng)建*筆者記住這個(gè)時(shí)候set集合至少有兩個(gè)記錄了A和B;

         *如果為空就b=new B0;創(chuàng)建一 個(gè)b對(duì)象;

         *再次說(shuō)明一一下關(guān)于實(shí)例化一 個(gè)對(duì)象,spring做的很復(fù)雜榜贴, 下次討論

         *創(chuàng)建完B的對(duì)象之后,接著完善B的生命周期

         *同樣也會(huì)判斷是否允許循環(huán)依賴,如果允許則把對(duì)象b存到第二 個(gè)map當(dāng)中;*提醒- -下筆者這個(gè)時(shí)候第二個(gè)map當(dāng)中至少有兩個(gè)對(duì)象了豌研, a和b

         *接著繼續(xù)生命周期;當(dāng)進(jìn)行到b對(duì)象的屬性填充的時(shí)候發(fā)覺b需要依賴A*于是就去容器看看A有沒有創(chuàng)建,說(shuō)白了就是從第一個(gè)map當(dāng)中去找a

         *有人會(huì)說(shuō)不上A在前面創(chuàng)建了a嘛?注意那只是個(gè)對(duì)象,不是bean;

         *還不在第一 個(gè)map當(dāng)中對(duì)所以b判定A沒有創(chuàng)建妹田,于是就是去創(chuàng)建A;*那么又再次回到了原點(diǎn),創(chuàng)建A的過程中;首先調(diào)用getBean("a")
         *上文說(shuō)到getBean("a")的核心就是getSingleton(beanName)

         * . 上文也說(shuō)了get出來(lái)a= =null;但是這次卻不等于空了

         *這次能拿出一個(gè)a對(duì)象;注意是對(duì)象不是bean

         *為什么兩次不同?原因在于getSingleton(beanName)的源碼

         * getSingleton(beanName)首先從第一個(gè)map當(dāng)中獲取bean

         *這里就是獲取a;但是獲取不到;然后判斷a是不是等于空

         *如果等于空則在判斷a是不是正在創(chuàng)建?什么叫做正在創(chuàng)建?

         *就是判斷a那個(gè)set集合當(dāng)中有沒有記錄A;

         *如果這個(gè)集合當(dāng)中包含了A則直接把a(bǔ)對(duì)象從map當(dāng)中g(shù)et出來(lái)并且返回*所以這一次就不等于空了鹃共,于是B就可以自動(dòng)注入這個(gè)a對(duì)象了

         *這個(gè)時(shí)候a還只是對(duì)象鬼佣,a這個(gè)對(duì)象里面依賴的B還沒有注入

         *當(dāng)b對(duì)象注入完成a之后,把B的周期走完,存到容器當(dāng)中

         *院之后繼續(xù)返回,返回到a注入b哪里?

         *因?yàn)閎的創(chuàng)建時(shí)因?yàn)閍需要注入b;于是去get b

         *當(dāng)b創(chuàng)建完成一個(gè)bean之后霜浴,返回b(b已經(jīng)是一個(gè)bean了)

         *要說(shuō)明的b是一個(gè)bean意味著bE 經(jīng)注入完成了a;這點(diǎn)上面已經(jīng)說(shuō)明了*于返迥了一個(gè)b,故而a也能注入b了;

         *接著a對(duì)象繼續(xù)完成生命周期晶衷,當(dāng)完之后a他在容器中了 到齜循環(huán)依賴搞定

         *需要說(shuō)明一下上墳提到的正在創(chuàng)建這種說(shuō)法并沒有防支持

         *要說(shuō)明一下文提到的正在創(chuàng)建這種說(shuō)法并沒有方支持

         *自己的認(rèn)為;各位讀者可以自行給他取名字

         *筆者是因?yàn)榇娣拍切┯涗浀膕et集合的名字叫做singletonsCurrentlyInCreation*顧名思義,當(dāng)前正在創(chuàng)建的單例對(duì)象阴孟。晌纫。。永丝。锹漱。

         *還有上文提到的對(duì)象和bean的概念;也沒有官方支持

         *也是筆為了讓讀者更好的理解spring源碼而提出的個(gè)人概念

         *但是如果你覺得這種方法確實(shí)能讓你更好的理解spring源碼

         *那么請(qǐng)姑且相信筆者對(duì)spring源碼的理解,假設(shè)10個(gè)人相信就會(huì)有100個(gè)人相信*繼而會(huì)有更多人相信慕嚷,就會(huì)成為官方說(shuō)法哥牍,哈哈。

         *以上是循環(huán)依賴的整個(gè)過程喝检,其中g(shù)etSingleton(beanName)

         *這個(gè)方法的存在至關(guān)重要

         *后說(shuō)明- - -下getSingleton(beanName)的源碼分析嗅辣,下文分析

         */
        Object sharedInstance = getSingleton(beanName);
        /**

         *如果sharedInstance不等于空直接返回

         *當(dāng)然這里沒有直接返回而是調(diào)用了getObjectForBeanInstance

         *關(guān)于這方法以后解釋,讀者可以認(rèn)為這里可以理解為

         * bean =sharedInstance;然后方法最下面會(huì)返回bean

         *什么時(shí)候不等于空?

         *再容器初始化完成之后.

         *程序員直接調(diào)用getbean的時(shí)候不等于空

         *什么時(shí)候等于空?

         *上已經(jīng)解釋過了,創(chuàng)建對(duì)象的時(shí)候調(diào)用就會(huì)等于空

         */
        if(sharedInstance != null && args == null) {
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        }
        else {
            /**

             *判斷這個(gè)類是不是在創(chuàng)建過程中

             *. 上文說(shuō)了蛇耀,一個(gè)類是否在創(chuàng)建的過程中是第二次調(diào)用getSingleton中決定的*這里還沒有執(zhí)行到辩诞,如果就在創(chuàng)建過程中則出異常

             **/
            //prototypesCurrentlyInCreation要聯(lián)系getSingleton方法
            if(isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }
            else {
                /**

                 *要說(shuō)明的筆者刪了很多和本文無(wú)用的代碼

                 *意思就是源碼中執(zhí)行到這個(gè)if的時(shí)候有很多其他代碼

                 *但是都是一 些判斷,很本文要討論的問題關(guān)聯(lián)不大

                 *這個(gè)if就是判斷當(dāng)前需要實(shí)例化的類是不是單例的

                 * spring默認(rèn)都是單例的纺涤,故而一般都成立的

                 *接下來(lái)便是調(diào)用第二_次 getSingleton

                 *第二次會(huì)把當(dāng)前正在創(chuàng)建的類記錄到set集合

                 *然后反射創(chuàng)建這個(gè)實(shí)例译暂,組起生命綢期

                 *第二次調(diào)用getSingleton的源碼分析會(huì)在下文
                 * **/
                if(mbd.isSingleton0) {
                    sharedInstance = getSingleton(beanName, () - > {
                    try {
                        //完成了目標(biāo)對(duì)象的創(chuàng)建
                        //如果要代理,還完成了代理
                        return createBean(beanName, mbd, args);
                    }
                    catch(BeansException ex) {
                        // Explicitly remove instance from singleton cache: It might have been put threre
                        // eagerly by the creation process, to allow for circular referencere solution
                        // Also remove any beans that received a temporary reference to the bean.
                        destroySingleton(beanName);
                        throw ех;
                    }
                        });
                    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }
                return(T) bean;
            }
        }
    }
    //第一次調(diào)用getSingleton99#Object sharedInstance = getSingleton(beanName);
    //空殼方法
    public Object getSingleton(String beanName) { //重點(diǎn)撩炊,-定要記住這里傳的是一個(gè)true, 面試會(huì)考
        return getSingleton(beanName, true);
    }
    /**

     . 上面說(shuō)的true對(duì)應(yīng)這里的第二 個(gè)參數(shù)boolean allowEarlyReference

     顧名思義叫做允許循環(huán)引用外永,而spring在內(nèi)部調(diào)用這個(gè)方法的時(shí)候傳的true

     這也能說(shuō)明spring默認(rèn)是支持循環(huán)引用的,這也是需要講過面試官的

     但是你不能只講這一點(diǎn),后面我會(huì)總結(jié),這里先記著這個(gè)true

     這個(gè)allowEarlyReference也是支持spring默認(rèn)支持循環(huán)引用的其中一個(gè)原因

     **/
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        /**首先spring會(huì)去第一個(gè)map當(dāng)中去獲取一 個(gè)bean;說(shuō)白了就是從容器中獲取

         說(shuō)明我們?nèi)绻谌萜鞒跏蓟笳{(diào)用getBean其實(shí)就從map中去獲取一個(gè)bean

         假設(shè)是初始化A的時(shí)候那么這個(gè)時(shí)候肯定等于空拧咳,前前分析過這個(gè)map的意義

         **/
        Object singletonObject = this.singletonObjects.get(beanName);
        /**

         我們這里的場(chǎng)景是初始化對(duì)象A第一次調(diào)用這個(gè)方法

         這段代碼非常重要伯顶,首先從容器中拿,如果拿不到,再判斷這個(gè)對(duì)象是不是在set集合

         這里的set集合前前E經(jīng)解釋過了骆膝,就是判斷a是不是正在創(chuàng)建

         假設(shè)現(xiàn)在a不在創(chuàng)建過程祭衩,那么直接返回一個(gè)空, 第一次getSingleton返回
         **/
        if(singletonObject == null && isSingletonCurrentlylnCreation(beanName)) lsynchronized(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;
    }
    //第二次調(diào)用getSingleton sharedInstance = getSingleton(beanName, 0) ->代碼我做了刪減,刪了一些本本文無(wú)關(guān)的代碼
    public Object getSingleton(String beanName, ObjectFactory <? > singletonFactory) {
        synchronized(this singletonObjects) {
            //首先也是從第一個(gè)map即容器中獲取
            //再次證明如果我們?cè)谌萜鞒跏蓟笳{(diào)用getBean其實(shí)就是從map當(dāng)中獲取一個(gè)bean//我們這里的場(chǎng)景是初始化對(duì)象A第一次調(diào)用這個(gè)方法
            //那么肯定為空
            Object singletonObject = this.singletonObjects.get(beanName);
            if(singletonObject == null) {
                /**注意這行代碼阅签,就是A的名字添加到set集合當(dāng)中

                 也就是筆者說(shuō)的標(biāo)識(shí)A正在創(chuàng)建過程當(dāng)中

                 這個(gè)方法比較簡(jiǎn)單我就不單獨(dú)分析了掐暮,直接在這里給出
                 這個(gè)方法比較簡(jiǎn)單我就不單獨(dú)分析了,直接在這里給出

                 singletonsCurrentlyInCreation.add就是放到set集合當(dāng)中

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

                 **/
                beforeSingletonCreation(beanName);
                boolean newSingleton = false;
                try {
                    //這里便是創(chuàng)建一個(gè)bean的入口乃
                    //spring會(huì)首先實(shí)例化一個(gè)對(duì)象, 然后生命周期
                    //走生命周期的時(shí)候前面說(shuō)過會(huì)判斷是否允許循環(huán)依賴
                    //如果允許則會(huì)把創(chuàng)建出來(lái)的這個(gè)對(duì)象放到第二個(gè)map當(dāng)中//然后接著生命周期當(dāng)他走到屬性填充的時(shí)候
                    //會(huì)去get- -下B政钟,因?yàn)橐畛銪,也就是大家認(rèn)為的自動(dòng)注入//這些代碼下文分析路克,如果完了生命周期
                    singletonObject = singletonFactory.getObject);
                    newSingleton = true;
                }
            }
            return singletonObject;
        }
    }
    //                              如果允許則會(huì)把創(chuàng)建出來(lái)的這個(gè)對(duì)象放到第個(gè)map當(dāng)中
//
//                              AbstractAutowireCapableBeanFactory#doCreateBean() Z?S31t45
//
//                              由于這個(gè)方法內(nèi)容過去多樟结,我刪減了 - 些無(wú)用代碼 上面說(shuō)的singletonObject =
//
//                                      singletonFactory.getObject();
//
//                              Ft @JbeaniAbstractAutowireCapableBeanFactory#doCreateBean(EêJ?bean;
//
//                              下面分析這個(gè)方法.
    protected Object doCreateBean(final String beanName, final RootBeanDefinitionmbd, final@ Nullable Object[] args) throws BeanCreationException {
        // Instantiate the bean.
        BeanWrapper instanceWrapper = null;
        if(mbd.isSingleton()) {
            //如果你bean指定需要通過factoryMethod來(lái)創(chuàng)建則會(huì)在這里被創(chuàng)建//如果讀者不知道上面factoryMethod那你就忽略這行代碼
            //你可以認(rèn)為你的A是一個(gè)普通類, 不會(huì)再這里創(chuàng)建
            instanceWrapper = this.factoryBeanlnstanceCache.remove(beanName);
            if(instanceWrapper == null)(
                    //這里就通過反射創(chuàng)建一個(gè)對(duì)象, 注意是對(duì)象不是bean
                    //iX↑c(diǎn)reateBeanlnstanceJiiFER, 4XTtGtT//以后如果有更新再來(lái)分析這個(gè)代碼
                    //讀者可以理解這里就是new了一個(gè)A對(duì)象
                    instanceWrapper = createBeanlnstance(beanName, mbd, args);
            //得到new出來(lái)的A,為什么需要得到呢?因?yàn)锳new出來(lái)之后存到一個(gè)對(duì)象的屬性當(dāng)中
            final Object bean = instanceWrapper.getWrappedlnstance);
            //厘點(diǎn):面試會(huì)考.
            //這里就是判斷是不是支持循環(huán)引|用和是否單例以及bean是否在創(chuàng)建過程中
            //判斷循環(huán)弓|用的是&& this. allowCircularReferences
            //allowCircularReferences在spring源碼當(dāng)中默認(rèn)就是true
            // private boolean allowCircularReferences = true; 這是spring源碼中的定義//并且這個(gè)屬性上面spring寫了-行徘常重要的注釋
            // Whether to automatically try to resolve circular references between beans//讀者自行翻譯,這是支持spring默認(rèn)循環(huán)引用最核心的證據(jù).
            //讀者-要講給面試官,關(guān)于怎么講,我后面會(huì)總結(jié)
            boolean earlySingletonExposure = (mbd.isSingleton0 && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
            //如果是單例,粗正在創(chuàng)建,瓶沒有關(guān)閉循環(huán)引|用則執(zhí)行
            //所以spring原形是不支持循環(huán)弓|用的這是證據(jù)精算,但是其實(shí)可以解決
            //怎么解決原形的循環(huán)依賴瓢宦,筆者下次更新吧
            if(earlySingletonExposure) {
                //這里就是這個(gè)創(chuàng)建出來(lái)的A對(duì)象a放到第二個(gè)map當(dāng)中//注意這里addSingletonFactory就是往map當(dāng)中put//需要說(shuō)明的是他的value并不是-個(gè)a對(duì)象
                /而是一段表達(dá)式,但是包含了這個(gè)對(duì)象的
                //所以上文說(shuō)的第二個(gè)map和第 三個(gè)map的有點(diǎn)不同
                //第三個(gè)map是直接放的a對(duì)象(下文會(huì)講到第三個(gè)map的),//第二個(gè)放的是一個(gè)表達(dá)式包含 了a對(duì)象
                //為什么要放一個(gè)表達(dá)式?下文分析吧
                addSingletonFactory(beanName, () - > getEarlyBeanReference(beanName, mbd, bean));
            }
            // Initialize the bean instance.Object exposedObject = bean;try {
            //填充屬性灰羽,也就是所謂的自動(dòng)注入//這個(gè)代碼我同一張圖來(lái)說(shuō)明
            //這個(gè)代碼我同一張圖來(lái)說(shuō)明
            poupetean(beaNname mbd, insteWrap exposedObject = ininlean(benlame eposedobject, mbd);
        }
        return exposedObject;
    }
    /**創(chuàng)建B的流程和創(chuàng)建A差不多驮履,把B放到set集合,標(biāo)識(shí)B正在創(chuàng)建,繼而實(shí)例化b對(duì)象,然后執(zhí)行生命周期流程,把創(chuàng)建的這個(gè)b對(duì)象放到第二個(gè)map當(dāng)中, 這個(gè)時(shí)候map當(dāng)中已經(jīng)有了a,b兩個(gè)對(duì)象谦趣。
     * 然后執(zhí)行b對(duì)象的屬性填充或者叫自動(dòng)注入時(shí)候發(fā)覺需要依賴a,于重復(fù)上面的getbean步驟疲吸,
     *調(diào)用getSingleton方法;只不過現(xiàn)在a對(duì)象已經(jīng)可以獲取了故而把獲取出來(lái)的a對(duì)象、臨時(shí)對(duì)象注入給b對(duì)象前鹅,然后走完b的生命周期流程后返回b所表示bean,跟著把這個(gè)b所表示的bean注入給a對(duì)象,
     * 最后走完a對(duì)象的其他生命周期流程;循環(huán)依賴流程全部走完;但是好像沒有說(shuō)到第3三個(gè)map,第三個(gè)map到底充當(dāng)了什么角色呢?
     * 這個(gè)知識(shí)點(diǎn)非常的重要峭梳,關(guān)于這個(gè)知識(shí)不少書籍和博客都說(shuō)錯(cuò)了舰绘,這也是寫這篇文章的意義;筆者說(shuō)每次讀spring源碼都不-樣的收獲, 這次最大的收獲便是這里了;我們先來(lái)看-下代碼;
     * 場(chǎng)景是這樣的葱椭,spring創(chuàng)建A,記住第一次創(chuàng)建A, 過程中發(fā)覺需要依賴B捂寿,于是創(chuàng)建B,創(chuàng)建B的時(shí)候發(fā)覺需要依賴A,于是再一-次創(chuàng)建- 第二次創(chuàng)建A,
     * 下面代碼就是基于第二次創(chuàng)建的A來(lái)分析;第二次創(chuàng)建A的時(shí)候依然會(huì)調(diào)用getSingleton,先獲取一下a
     **/
    protected Object getSingleton(String beanName, boolean allowEarlyReference) { //先從第一個(gè)map獲取a這個(gè)bean, 也就是單例池獲取
        Object singletonObject = this singletonObjects.get(beanName);
        if(singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            if(singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
                synchronized(this.singletonObjects) {
                    //然后從第三個(gè)map當(dāng)中獲取a這個(gè)對(duì)象
                    singletonObject = this.earlySingletonObjects get(beanName);
                    //如果第三個(gè)map獲取不到a對(duì)象,再看是否允許了循環(huán)引用
                    //                                          而這里的allowEarlyReference是true
                    //
                    //                                          1 為什么是true,.文說(shuō)了這個(gè)方法是spring自 己調(diào)用的孵运,他默認(rèn)傳了true
                    if(singletonObject == null && allowEarlyReference) {
                        //然后從第二個(gè)map中獲取一個(gè)達(dá)式
                        //這要非常注意第二個(gè)map當(dāng)中存的不是一 個(gè) 單純的對(duì)象
                        //前面說(shuō)了第二個(gè)map當(dāng)中存的是一個(gè)表達(dá)式秦陋, 你可以理解為存了一個(gè)廠//或者理解存了一個(gè)方法,方法里面有個(gè)參數(shù)就是這個(gè)對(duì)象
                        //安裝spring的命名來(lái)分析應(yīng)該理解為一個(gè)廠singletonFactory
                        //一個(gè)能夠生成a對(duì)象的工廠
                        //那么他為什么需要這么一個(gè)廠
                        //這里我先大概說(shuō)一下治笨,為了過工廠來(lái)改變這個(gè)對(duì)象
                        //至于為什么要改變對(duì)象,下文我會(huì)分析
                        //當(dāng)然大部分情況下是不要改變這個(gè)對(duì)象的
                        //讀者先可以考慮不需要改變這個(gè)對(duì)象,
                        //那么這個(gè)map里面存的工廠就生產(chǎn)就是這個(gè)原對(duì)象,那么和第三個(gè)map功能-樣
                        ObjectFactory <? > singletonFactory = this.singletonFactories get(beanName);
                        if(singletonFactory != nul) {
                            //調(diào)用表達(dá)式驳概,說(shuō)白了就是調(diào)用工廠的方法,然后改變對(duì)象
                            //我們假設(shè)對(duì)象不需要改變的情況那么返回了原對(duì)象就是a
                            //需要改變的情況我們文再分享
                            singletonObject = singletonFactory.getObject0;
                            //然后把這個(gè)對(duì)象放到第三個(gè)map當(dāng)中
                            this.earlySingletonObjects.put(beanName, singletonObject);
                            //把這個(gè)對(duì)象旷赖、或者表達(dá)式顺又、或者廠從第二個(gè)map中移除
                            this.singletonFactories.remove(beanName);
                            //厘點(diǎn):面試會(huì)考--為什么要放到第三三個(gè)?為什么要移除第二個(gè)?
                            //首先我們通過分析做一個(gè)總結(jié):
                            //                                                  spring首先從第一個(gè)map中拿 a這個(gè)bean
                            //                                                  不到,從第三個(gè)map當(dāng)中拿a這個(gè)對(duì)象
                            //
                            //                                          不到,從第二個(gè)map拿a這個(gè)對(duì)象或者工廠
                            //
                            //                                          拿到之后放到第三個(gè)map,移除第_一個(gè)map里面的表達(dá)式等孵、或者廠
                            //
                            //                                          如果對(duì)象需要改變稚照,當(dāng)改變完成之后就把他放到第三個(gè)里面
                            //
                            //                                          這里的情況是b需要a而進(jìn)行的步驟,試想- -下以后如果還有C需要依賴a
                            //
                            //                                          就不需要重復(fù)第二個(gè)map的工作 了,也就是改變對(duì)象的工作了俯萌。
                            //
                            //                                          因?yàn)楦淖兺瓿芍蟮腶對(duì)象已經(jīng)在第三個(gè)map中了果录。不知道讀者能不能懂筆者的意思如果對(duì)象不需要改變道理是一樣的, 也同樣在第三個(gè)map取就是了;
                            //
                            //                                          于為什么需要移除第二個(gè)map里面的工廠咐熙、 或者表達(dá)式就更好理解 了
                            //
                            //                                          他E經(jīng)對(duì)a做完了改變,改變之后的對(duì)象已經(jīng)在第三個(gè)map了,為為方便gc啊下面對(duì)為什么需要改變對(duì)象做分
                        }
                    }
                    return singletonObject;
                }
            }
        }
    }
    //                                          為什么需要改變對(duì)象?那個(gè)表達(dá)式弱恒、或者說(shuō)工廠主要干什么事呢?那個(gè)工廠、或者表達(dá)式主要是調(diào)用了下面這個(gè)方法
    //關(guān)于后置處理器筆者其實(shí)要說(shuō)話很多很多
    //現(xiàn)在市面上可見的資料或者書籍對(duì)后置處理器的說(shuō)法筆者-般都不同
    //我在B站上傳過一個(gè)4個(gè)小時(shí)的視頻, 其中對(duì)spring后處理器做了詳細(xì)的分析//也提出了-自己的理解和主流理解不同的地方糖声,有興趣同學(xué)可以去看看
    //其實(shí)簡(jiǎn)單說(shuō)-這個(gè)方法作用主要是為了來(lái)處理aop的;
            斤彼、
                    /當(dāng)然還有其他功能分瘦,但是一般的讀者 最熟悉的就是aop
    //這里我說(shuō)明一下,aop的原理或者流程有很多書籍說(shuō)到過
    //但是筆者今天親測(cè)了,現(xiàn)在市面可見的資料和書籍對(duì)aop的說(shuō)法都不全
    //很多資料提到aop是在spring bean的生命周期里面填充屬性之后的代理期完成的/而這個(gè)代理周期甚至是在執(zhí)行生命周期回調(diào)方法之后的一個(gè)周期
    //那么問題來(lái)了?什么叫spring生命周期回調(diào)方法周期呢?
    //首先spring bean生命周期和spring生命周期回調(diào)方法周期是兩個(gè)概念
    //spring生命周期回調(diào)方法是spring bean生命周期的一部分琉苇、或者說(shuō)一個(gè)周期
    //簡(jiǎn)單理解就是spring bean的生命的某個(gè)過程會(huì)去執(zhí)行spring的生命周期的回調(diào)方法
    //此如你在某個(gè)bean的方法上面寫一個(gè)加@ PostConstruct的方法(一 般稱bean初始化方法)
    //那么這個(gè)方法會(huì)在spring實(shí)例化一個(gè)對(duì)象之 后嘲玫,琉屬性之后執(zhí)行這個(gè)加注解的方法//我這里叫做spring生命周期回調(diào)方法的生命周期,不是我胡說(shuō)并扇,有官方文檔可以參考的
    //在執(zhí)行完spring生命周期回調(diào)方法的生命周期之后才會(huì)執(zhí)行代理生命周期
    //在代理這個(gè)生命周期當(dāng)中如果有需要會(huì)完成aop的功能
    //以上是現(xiàn)在主流的說(shuō)法去团,也是一般書籍或者"某些大師”的說(shuō)法
    //但是在循環(huán)引用的時(shí)候就不一樣了,循環(huán)弓l用的情況下這個(gè)周期這里就完成了aop的代理//這個(gè)周期嚴(yán)格意義上是在填充屬性之前(填充屬性也是一個(gè)生命周期階段)
    //填充屬性的周期甚至在生命周期回調(diào)方法之前穷蛹,更在代理這個(gè)周期之前了
    //簡(jiǎn)單來(lái)說(shuō)主流說(shuō)法代理的生命周期比如在第8個(gè)周期或者第八步吧
    //但是筆者這里得出的結(jié)論土陪,如果- -個(gè)bean是循環(huán)引用的則代理的周期可能在第3步就完成了//那么為什么需要在第三步就完成呢?
    //試想一下A、 B兩個(gè)類,現(xiàn)在對(duì)A類做aop處理,也就是需要對(duì)A代理
    //
    //                                          不考慮循環(huán)引用spring實(shí)例化A,然后生命周期確實(shí)在第8個(gè)周期完成的代理關(guān)于這個(gè)結(jié)論可以去看b站我講的spring aop源碼分析
    //
    //                                          但是如果是循環(huán)依賴就會(huì)有問題
    //
    //                                                  比如spring實(shí)例化A然后發(fā)現(xiàn)需要注入B這個(gè)時(shí)候A還沒有走到8步
    //
    //                                          還沒有完成代理肴熏,發(fā)覺需要注入B,便去創(chuàng)建B,創(chuàng)建B的時(shí)候
    //
    //                                          發(fā)覺需要注入A,于是創(chuàng)建A,創(chuàng)建的過程中通過getSingleton
    //
    //                                          得到了a對(duì)象鬼雀,注意是對(duì)象,-個(gè)沒有完成代理的對(duì)象
    //
    //                                          然后把這個(gè)a注入給B?這樣做合適嗎?注入的a根本沒有aop功能;顯然不合適因?yàn)閎中注入的a需要是一個(gè)代理對(duì)象
    //
    //                                                  而這個(gè)時(shí)候a存在第二個(gè)map中; 不是一個(gè)代理對(duì)象;
    //
    //                                          于是我在第二個(gè)map中就不能單純的存一個(gè)對(duì)象蛙吏, 要存一個(gè)廠
    //
    //                                          這個(gè)廠在特殊的時(shí)候需要對(duì)a對(duì)象做改變,比如這里說(shuō)的代理(需要aop功能的情況)這也是三個(gè)map存在的必要性,不知道讀者能不能get到點(diǎn)
    protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
        Object exposedObject = bean;
        if(!mbd.isSynthetic( && haslnstantiationAwareBeanPostProcessors) {
            for(BeanPostProcessor bp: getBeanPostProcessors()) {
                if(bp instanceof SmartlnstantiationAwareBeanPostProcessor) {
                    SmartInstantiationAwareBeanPostProcessor ibp = (SmartlnstantiationAwareBeanPostProcessor) bp;
                    exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
                }
            }
        }
        return exposedObject;
    }
    //                                          總結(jié)關(guān)于循環(huán)引用源哩,如何回答面試:
    //
    //                                          首先spring在單例的情況下是默認(rèn)支持循環(huán)引用的(當(dāng)然原形也有辦法,今天先不討論);
    //
    //                                          在不做任何配置的情況下鸦做,兩個(gè)bean相互依賴是能初始化成功的; spring源碼中在創(chuàng)建bean的時(shí)候先創(chuàng)建這個(gè)bean的對(duì)象励烦,創(chuàng)建對(duì)象完成之后通過判斷容器對(duì)象的
    //
    //                                                  allowCircularReferences屬性決定是否允許緩存這個(gè)臨時(shí)對(duì)象,如果能被緩存成功則通過緩存提前暴露這個(gè)臨時(shí)對(duì)象來(lái)完成循環(huán)依賴;
    //
    //                                          而這個(gè)屬性默認(rèn)為true,所以說(shuō)spring默認(rèn)支持循環(huán)依賴的,但是這個(gè)屬性spring提供了api讓程序員來(lái)修改泼诱,所以spring也提供了關(guān)閉循環(huán)引l用的功能;
    //
    //                                          再就是spring完成這個(gè)臨時(shí)對(duì)象的生命周期的過程中當(dāng)執(zhí)行到注入屬性或者自動(dòng)裝配的周期時(shí)候會(huì)通過getSingleton方法去得到需要注入的b對(duì)象;
    //
    //                                          而b對(duì)象這個(gè)時(shí)候肯定不存在故而會(huì)創(chuàng)建b對(duì)象創(chuàng)建b對(duì)象成功后繼續(xù)b對(duì)象的生命周期坛掠,當(dāng)執(zhí)行到b對(duì)象的自動(dòng)注,入周期時(shí)候會(huì)要求注入a對(duì)象;
    //
    //                                          調(diào)用getSingleton;從map緩存中得到a的臨時(shí)對(duì)象(因?yàn)檫@個(gè)時(shí)候a在set集合中;這里可以開講)治筒, 且獲取的時(shí)候也會(huì)判斷是允許循環(huán)弓用,但是判斷的這個(gè)值是通過參數(shù)傳進(jìn)來(lái)的屉栓,也就是spring內(nèi)部調(diào)用的,spring源碼當(dāng)中寫死了為true,故而如果需要擴(kuò)展spring矢炼、或者對(duì)spring=次開發(fā)的的時(shí)候程序員可以自定義這個(gè)值來(lái)實(shí)現(xiàn)自己的功能;不管放到緩存還是從緩存中取出這個(gè)臨時(shí)都需要判斷;而這兩次判斷spring源碼當(dāng)中都是默認(rèn)為true; 這里也能再次說(shuō)明spring默認(rèn)是支持循環(huán)引用的;
    //
    //                                          然后面試中可以在說(shuō)說(shuō)兩次調(diào)用getSingleton的意義系瓢,正在創(chuàng)建的那個(gè)set集合有什么用;最后在說(shuō)說(shuō)你在看spring循環(huán)引用的時(shí)候得出的aop實(shí)例化過程的新發(fā)現(xiàn);就比較完美了
    //
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市句灌,隨后出現(xiàn)的幾起案子夷陋,更是在濱河造成了極大的恐慌,老刑警劉巖胰锌,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件骗绕,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡资昧,警方通過查閱死者的電腦和手機(jī)酬土,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)格带,“玉大人撤缴,你說(shuō)我怎么就攤上這事刹枉。” “怎么了屈呕?”我有些...
    開封第一講書人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵微宝,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我虎眨,道長(zhǎng)蟋软,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任嗽桩,我火速辦了婚禮岳守,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘碌冶。我一直安慰自己湿痢,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開白布扑庞。 她就那樣靜靜地躺著蒙袍,像睡著了一般。 火紅的嫁衣襯著肌膚如雪嫩挤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,829評(píng)論 1 290
  • 那天消恍,我揣著相機(jī)與錄音岂昭,去河邊找鬼。 笑死狠怨,一個(gè)胖子當(dāng)著我的面吹牛约啊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播佣赖,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼恰矩,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了憎蛤?” 一聲冷哼從身側(cè)響起外傅,我...
    開封第一講書人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎俩檬,沒想到半個(gè)月后萎胰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡棚辽,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年技竟,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片屈藐。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡榔组,死狀恐怖熙尉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情搓扯,我是刑警寧澤检痰,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站擅编,受9級(jí)特大地震影響攀细,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜爱态,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一谭贪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧锦担,春花似錦俭识、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至磁椒,卻和暖如春堤瘤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背浆熔。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工本辐, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人医增。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓慎皱,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親叶骨。 傳聞我的和親對(duì)象是個(gè)殘疾皇子茫多,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容