1. 程式人生 > >Spring 原始碼閱讀之 深入理解 finishBeanFactoryInitialization

Spring 原始碼閱讀之 深入理解 finishBeanFactoryInitialization

原始碼入口

上篇博文中我們看到了將Spring環境中的 BeanPostProcessor找出來,新增到BeanFactory中的beanPostProcessors中,統一維護,本片博文繼續往下拓展,看下Spring如何例項化bean,以及如何實現在bean的例項化通過各種各樣的後置處理器完成bean的增強

所以本次的程式入口是AbstractApplicationContext中的finishBeanFactoryInitialization(beanFactory);,原始碼如下,主要做了如下幾件事


protected 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));
    }

    // 檢查上下文中是否存在型別轉換器
    if (!beanFactory.hasEmbeddedValueResolver()) {
        beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
    }
    // 儘早初始化LoadTimeWeaverAware bean,以便儘早註冊它們的轉換器。
    // 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
    // 允許快取所有的bean的定義資料
    beanFactory.freezeConfiguration();

    // Instantiate all remaining (non-lazy-init) singletons.
    // 準備例項化bean
    beanFactory.preInstantiateSingletons();
}

我們著重看他是如何建立例項化bean的,跟進beanFactory.preInstantiateSingletons();,呼叫beanFactory的方法準備例項化bean, 這個beanFactory就是Spring預設是bean工廠, DefaultListableBeanFactory, 原始碼如下:方法不算很長,邏輯也很清楚, 一開始Spring取出當前上下文中所有的BeanName列表,因為在執行到這裡之前,已經完成包掃描了所以說這個盛放beanName的list裡面存放的就是所有的需要例項化的物件的全集,包含Spring自己的,和程式設計師自己新增的還包含Aspectj的

所以說,當前方法的目標很明瞭,就是遍歷這個list中的每一個beanName,然後例項化當前beanName相應的bean

當然,如果想例項化,前提是不能是抽象類,不能是介面,非懶載入, 而且針對FactoryBean還有不同的處理模式

public void preInstantiateSingletons() throws BeansException {
if (logger.isDebugEnabled()) {
    logger.debug("Pre-instantiating singletons in " + this);
}
//所有bean的名字
// 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.
//todo 遍歷一個副本以允許init方法,而init方法反過來註冊新的bean定義。
// todo 盛放所有的beanName,所有的需要例項化的beanName都在這裡,包括Spring斷斷續續新增的, Aspectj的, 程式設計師通過註解標識的
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

// Trigger initialization of all non-lazy singleton beans...
// todo 觸發所有非延遲載入單例beans的初始化,主要步驟為呼叫getBean
for (String beanName : beanNames) {

    // todo 合併父類BeanDefinition,可以進入檢視
    RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);

    //todo 三個條件,抽象,單例,非懶載入
    if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {

        if (isFactoryBean(beanName)) {
            Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
            // todo 如果是FactoryBean則加上&
            // todo 檢驗是否是 FactoryBean 型別的物件
            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 {
            // todo 因為我們沒有新增FactoryBean型別的物件, 一般都會進入這個getBean
            getBean(beanName);
        }
    }
}

下面接著跟進getBean(beanName);方法,顧名思義獲取Bean,再往下跟下去,就算是本文的正文開始部分了,但是我想在這裡級具體一下,一個比較有分量的劇透吧,當前的getBean(beanName)它是有返回值的,一會當我們往下跟進的是時候會發現會存在遞迴的現象,這一點巧妙的實現了@Autowired處理setter方式實現迴圈引用

ok,現在繼續看程式碼,經過了幾個空方法的傳遞,我們來到下面的程式碼中,它主要做了如下幾件事

首先將傳遞進來的name轉換成了beanName

原因1: FactoryBean的實現類的儲存方式和其他的類完全相同,新增上&是獲取不到的, 因此我們將&去掉 原因2: 解決別名的問題

為什麼在建立bean之前先呼叫getSingleton()?

回想一下,現在是Spring啟動的過程中,是在準備例項化bean,為什麼一開始就來getSingleton(),跟進原始碼檢視這個方法,它最終實現中有一行程式碼是這樣的Object singletonObject = this.singletonObjects.get(beanName);而這個singletonObjects就是微觀層面的IOC容器,迴圈建立剛開始時,IOC確實是空的,但是我前面存在劇透,一開始的getBean()方法是存在遞迴呼叫現象的,直接舉2個例子: 第一:假如現在在例項化A,結果有發現需要給A注入B, 那Spring是不是得獲得B,怎麼獲得呢? 遞迴使用getBean(BName)完成, 第二個例子: A被新增上了@Lazy註解,是懶載入的,但是終究有一個會通過getBean(AName)獲取A,這是發現A是例項化需要B,B肯定已經例項化完事了,同樣是通過遞迴getBean(BName)實現注入, 在這兩個過程中就是getSingleton()保證不會重複建立已經存在的例項

我們關注的重點其實是第二個getSingleton(beanName()->{xxx})

在第二個getSingleton()方法中才是真正的去例項化bean的方法

最後,在當前的方法最後將bean返回了

前面我就是說過了,getBean(beanName)存在遞迴呼叫的情況,為什麼我會一直說這個事呢,因為如果不知道這個事的話,這些程式碼看起來是沒有頭緒的,但是明白這個事,看程式碼就變得很有邏輯,我在簡單總結一下怎個玩這個遞迴呢? 假設現在通過getBean(AName)來注入A物件,但是呢發現了A依賴B物件,於是在getBean(AName)裡面呼叫getBean(BName),通過這個方法返回出B物件完成A的注入

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
    @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

// 將傳遞進來的name
final String beanName = transformedBeanName(name);
Object bean;

// Eagerly check singleton cache for manually registered singletons.
// 及早的檢查一下有沒有已經註冊了的單例物件
Object sharedInstance = getSingleton(beanName);// todo ::: name=myService時,這次來呼叫的就是 DefaultSingletonBeanRegistry中的 getSingleton() , 不同之處是多傳遞了一個true
if (sharedInstance != null && args == null) {
    // 如果存在的話,將其取出賦值給bean,後續直接返回這個bean
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
} else {
    // Fail if we're already creating this bean instance:
    // We're assumably within a circular reference.
    // 來到這裡就說明要獲取的bean還沒有例項化過
    // 於是檢驗一下,如果是原形,直接拋異常
    if (isPrototypeCurrentlyInCreation(beanName)) {
        throw new BeanCurrentlyInCreationException(beanName);
    }

    // Check if bean definition exists in this factory.
    // 檢查是否存在預設的父工廠
    BeanFactory parentBeanFactory = getParentBeanFactory();
    if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
        // Not found -> check parent.
        String nameToLookup = originalBeanName(name);
        if (parentBeanFactory instanceof AbstractBeanFactory) {
            return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                    nameToLookup, requiredType, args, typeCheckOnly);
        }
        else if (args != null) {
            // Delegation to parent with explicit args.
            return (T) parentBeanFactory.getBean(nameToLookup, args);
        }
        else {
            // No args -> delegate to standard getBean method.
            return parentBeanFactory.getBean(nameToLookup, requiredType);
        }
    }

    if (!typeCheckOnly) {
        // 將當前的beanName存放到AlreadeyCreated這個set集中,標識這個bean被建立了
        markBeanAsCreated(beanName);
    }

    try {
        final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
        checkMergedBeanDefinition(mbd, beanName, args);

        // Guarantee initialization of beans that the current bean depends on.
        // 確保當前bean所依賴的bean都已經初始化好了
        String[] dependsOn = mbd.getDependsOn();
        if (dependsOn != null) {
            for (String dep : dependsOn) {
                if (isDependent(beanName, dep)) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                            "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                }
                registerDependentBean(dep, beanName);
                try {
                    getBean(dep);
                }
                catch (NoSuchBeanDefinitionException ex) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                            "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                }
            }
        }

        // Create bean instance.
        if (mbd.isSingleton()) {
          // 例項化bean
            sharedInstance = getSingleton(beanName, () -> { 
                    // 真正的完成bean的建立
                    return createBean(beanName, mbd, args);
            
            });

            bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
        }
        // 下面是進行其他的檢查工作,這裡不再深究了
        else if (mbd.isPrototype()) {
            // It's a prototype -> create a new instance.
            Object prototypeInstance = null;
            try {
                beforePrototypeCreation(beanName);
                prototypeInstance = createBean(beanName, mbd, args);
            }
            finally {
                afterPrototypeCreation(beanName);
            }
            bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
        }

        else {
            String scopeName = mbd.getScope();
            final 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, () -> {
                    beforePrototypeCreation(beanName);
                    try {
                        return createBean(beanName, mbd, args);
                    }
                    finally {
                        afterPrototypeCreation(beanName);
                    }
                });
                bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
            }
            catch (IllegalStateException ex) {
                throw new BeanCreationException(beanName,
                        "Scope '" + scopeName + "' is not active for the current thread; consider " +
                        "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                        ex);
            }
        }
    }
    catch (BeansException ex) {
        cleanupAfterBeanCreationFailure(beanName);
        throw ex;
    }
}

// Check if required type matches the type of the actual bean instance.
if (requiredType != null && !requiredType.isInstance(bean)) {
    try {
        T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
        if (convertedBean == null) {
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
        }
        return convertedBean;
    }
    catch (TypeMismatchException ex) {
        if (logger.isDebugEnabled()) {
            logger.debug("Failed to convert bean '" + name + "' to required type '" +
                    ClassUtils.getQualifiedName(requiredType) + "'", ex);
        }
        throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
    }
}
return (T) bean;
}

經過了上面一頓扯,然後我們繼續往下跟,看看createBean(beanName, mbd, args)方法中是如何例項化我們的Bean的, 上面的方法是在AbstractBeanFactory中,createBean(beanName, mbd, args)是它的抽象方法, 那實現類是哪個呢?

AbstractAutowireCapableBeanFactory,隆重的誇一下這個類,Spring都稱讚這個類是有有才華的

todo 總結這個類

在這個方法中,主要做了兩件事:兩件大事!!!

第一件大事:

在例項化Bean前,第一次呼叫後置處理器, 這件大事絕對是有歷史意義的!!!為啥呢?大家想想,bean還沒有建立呢!就已經可以插手bean的建立過程了,不是很刺激嗎?接著看回調了什麼後置處理器呢? Spring會迴圈所有的處理器檢查當前被遍歷的處理器是否是InstantiationAwareBeanPostProcessor型別的,如果是的話呢,就執行這個後置處理器的postProcessBeforeInstantiation(beanClass, beanName);方法

這個postProcessBeforeInstantiation()是允許有返回值的,大家可以想想,這一點是不是有點可怕? 事實也是這樣,後置處理器的目的是為了增強物件,而我們卻可以在這裡返回一個任何東西,狸貓換臺子替換掉原始的,還沒有被建立的物件,還有一點,就是一旦我們在這裡真的是沒有返回null,那後續Spring就沒有義務在去為我們建立本來應該建立的物件了,程式碼通過if-else的選擇分支會使得當前的物件不再經歷其他後置處理器的增強,最終執行它父類的postProcessorAfterInitialization()

補充一點,我們通過@EnableAspectjAutoProxy新增到Spring上下文中的AnnotationAwareAspectjAutoProxyCreator物件其實就是這個型別InstantiationAwareBeanPostProcessor,也就是說在這裡這個介面的相關方法會被回撥,下面看看他的實現類AbstractAutoProxyCreator對這個before()方法的重寫實現,原始碼如下:

主要邏輯就是找出需要產生代理增強的bean(切面類),和普通的bean, 需要增強的bean放在advisedBeans裡面,因為需要增強的bean是需要動態植入其他邏輯的,所以不放在一起

判斷當前bean是否是基礎型別的,比如: Advice PointCut Advisor AopInfrastructureBean 或者是 切面Aspectj 都算是基礎型別,標註這些資訊的類,是不會被增強的,標記false

主意啊,上面說的都是作用都是進行了一下標記

//todo 跟進來
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
    Object cacheKey = getCacheKey(beanClass, beanName);

    if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
        if (this.advisedBeans.containsKey(cacheKey)) {
            return null;
        }
        // todo 亮點就是在這裡,  如果是我們切面類來到這裡,條件是滿足的
        // todo advicedBeans    見名知意: 通知beans
        // todo Spring用它標識,  被放在這個方法中的類,全部都不會被增強
        // todo 滿足什麼條件時,通過檢查呢? 就是檢查是否標記有 @Aspectj  @Before ... 等註解

        // todo 說的再直接一點, 就是返回了null, 表示當前的切面仍然需要按照正常的流程創建出來,但是這裡進行標記了
        if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return null;
        }
    }

    // Create proxy here if we have a custom TargetSource. todo 如果我們有一個自定義的TargetSource,在這裡建立代理
    // Suppresses unnecessary default instantiation of the target bean: // todo 抑制不必要的目標bean的預設例項化:
    // The TargetSource will handle target instances in a custom fashion. todo TargetSource將以自定義方式處理目標例項。
    TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
    if (targetSource != null) {
        if (StringUtils.hasLength(beanName)) {
            this.targetSourcedBeans.add(beanName);
        }
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
        Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }

    return null;
}

經過上面的標記,在哪裡產生的代理物件呢?其實是在AbstractAutowireCapeableBeanFactory中的initializeBean()方法中實現的postProcessAfterInitialization()實現的,在本文的末尾展開討論


第二件大事: 例項化物件, 繼續跟進

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.
    // todo 做各種各樣的屬性值的賦值, 比如這種 通過Spring的Bean傳遞給Spring框架的值  ==> bd.setPropertyValue("aaa")
    Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
        mbdToUse = new RootBeanDefinition(mbd);
        mbdToUse.setBeanClass(resolvedClass);
    }

    // Prepare method overrides.
    // todo 處理 lookup-method 和 replace-method 配置,Spring 將這兩個配置統稱為 override method
    try {
        mbdToUse.prepareMethodOverrides();
    }
    catch (BeanDefinitionValidationException ex) {
        throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
                beanName, "Validation of method overrides failed", ex);
    }

    try {
        // todo 在例項化之前完成一次解析操作,這也是
        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 {
        //todo 呼叫 doCreateBean 建立bean
        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        if (logger.isDebugEnabled()) {
            logger.debug("Finished creating instance of bean '" + beanName + "'");
        }
        return beanInstance;
    }
}

我們繼續跟進doCreateBean(beanName, mbdToUse, args);方法, 同樣是本類AbstarctAutowireCapableBeanFactory的方法,原始碼如下: 這個方法也是無與倫比的重要,那這個方法中做了什麼事情呢?如下

  • 建立一個 BeanWrapper,用來存放bean+其他屬性
  • 建立bean的例項,封裝進上面的BeanWrapper中
  • 分兩次呼叫處理處理器
  • 設定屬性,填充屬性
  • 經過AOP處理,將原生物件轉換成Proxy
  • 返回BeanWrapper

因為這個方法簡直太重要了,上面列舉的每一點都值得我們仔細分析,我們每一條的分析都寫在下面程式碼的下面

    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
            throws BeanCreationException {

        // Instantiate the bean.
        // todo BeanWrapper 用來包裝bean
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            // todo 一開始 factoryBeanInstanceCache 這個map中是沒有值的, 所以進入下面的if
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {

            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        // todo !!!!!!!!這裡獲取出來的物件是原生物件!!!!!!!!!!!!
        final 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");
            }

            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }

        // Initialize the bean instance.
        Object exposedObject = bean; // todo 到目前為止還是原生物件
    
            //todo  用來填充屬性
            //設定屬性,非常重要
            populateBean(beanName, mbd, instanceWrapper);
            
            // todo 經過AOP處理,原生物件轉換成了代理物件,跟進去
            //執行後置處理器,aop就是在這裡完成的處理
            exposedObject = initializeBean(beanName, exposedObject, mbd);
    
        return exposedObject;
    }

例項化物件

我把原始碼貼在了下面,下面方法的目的就是選出一個策略來例項化一個物件, 那有什麼策略呢? 這就看程式設計師是怎麼配置的了, 程式設計師可以配置工廠方法,指定構造方法,或者是程式設計師沒有做出任何干涉,讓Spring按自己的方式去例項化

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
        // Make sure bean class is actually resolved at this point.
        Class<?> beanClass = resolveBeanClass(mbd, beanName);

        /**
         * todo 檢測一個類的訪問許可權, Spring預設是 允許訪問非public型別的方法
         */
        if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
        }

        /**
         *  建立一個bean的快捷方式
         */
        boolean resolved = false;
        boolean autowireNecessary = false; // todo 是否是必須自動裝配
        if (args == null) {
            synchronized (mbd.constructorArgumentLock) {

                // todo
                if (mbd.resolvedConstructorOrFactoryMethod != null) {
                    resolved = true;
                    //如果已經解析了構造方法的引數,則必須要通過一個帶參構造方法來例項
                    autowireNecessary = mbd.constructorArgumentsResolved;
                }
            }
        }

        if (resolved) {
            if (autowireNecessary) {// todo 如果是需要自動注入的,就使用構造方法自動注入
                // 通過構造方法自動裝配的方式構造 bean 物件
                return autowireConstructor(beanName, mbd, null, null);
            }
            else {
                //通過預設的無參構造方法進行
                //todo 通過預設的無參構造方法
                return instantiateBean(beanName, mbd);
            }
        }

        Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
        if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
                mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
            // todo 使用特定的構造方法完成自動裝配
            return autowireConstructor(beanName, mbd, ctors, args);
        }

        // No special handling: simply use no-arg constructor.
        //todo 使用預設的無參構造方法進行初始化
        return instantiateBean(beanName, mbd);
    }

我們主要關注上面程式碼的determineConstructorsFromBeanPostProcessors(beanClass, beanName)這個方法的目的就是推測例項化需要的構造方法, 為什麼需要先推測構造方法呢? 因為Spring例項化物件時,需要使用特定的構造方法才能反射出物件,這時如果程式設計師指定了帶引數的構造方法,spring就會使用這個構造方法例項化物件,如果程式設計師提供了一個不帶任何引數的預設構造方法,Spring會忽略它,按自己的邏輯使用預設的無參構造

所以上面的if-else分支目的很明確,先是嘗試獲取全部的構造方法,然後看看有沒有解析出來構造方法, 解析出來的話,就使用第一種邏輯,按照 特殊的構造方法模式進行處理,有解析出來,就使用預設的構造方法

我們進一步跟進這個determineConstructorsFromBeanPostProcessors(beanClass, beanName)方法,可以發現方法裡面又是一波後置處理器的回撥工作,這次選出的後置處理器的型別是SmartInstantiationAwareBeanPostProcessor,見名知意,這種處理器可以感知到心儀的構造方法,它的主要實現邏輯就是,檢視這個將被例項化的物件中有沒有添加了@Lookup註解的方法,有的話為這種方法生成代理,迴圈遍歷所有的構造方法,看看這些構造方法上存在不存在@Value或者@Autowired註解,因為這些註解中存在required=true,只要存在這種註解,Spring就將他當成候選的構造方法,但是如果存在多個的話,Spring也不知道到底用哪一個,但是在這裡Spring會將所有符合條件的都選出來,但是一般情況下,都可以正確的選出合適的構造

選擇出合適構造方法之後,就根據不同的構造方法,選擇使用不同的方式去例項化物件, 都有什麼方式呢? 兩種方式

方式1:

這是比較複雜的方式,此時Spring需要在這個方法記憶體比較好幾個候選的構造方法,計算它們的差異值,最終值最小的建構函式就是將要用來例項化物件的建構函式,當然很可能是選不出合適的建構函式的,於是Spring沒有立即丟擲異常,而是將異常新增進bean工廠的suppressedExceptions這個set集合中

如果成功的選擇出來一個建構函式,就會使用jdk原生的反射機制,例項化一個物件

 autowireConstructor(beanName, mbd, ctors, args);

方式2:

直接使用JDK原生的反射機制,例項化一個物件

instantiateBean(beanName, mbd);

小結:

程式碼看到這裡,方才說的有才華的那個類AbstactAutowiredCapatableBeanFactory中的doCreateBean()方法的instanceWrapper = createBeanInstance(beanName, mbd, args); 也就看完了, 到這裡也就知道了,Spring會先把所有滿足條件的bean全部例項化存放起來,這裡的物件是百分百原生java物件,不摻水不含糖

接著往下看,我把程式碼重寫貼出來, 下面還有五件大事,這四件大事說完了,本文就結束了

第一: 是applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); 回撥後置處理器,進行有關注解的快取操作

第二: 是getEarlyBeanReference(beanName, mbd, bean) 獲取一個提早暴露的beanDefinition物件,用於解決迴圈依賴問題

第三: 將剛才建立原生java物件存放一個叫singletonFactories的map中,這也是為了解決迴圈依賴而設計的資料結構,舉個例子: 現在準備建立A例項, 然後將A例項新增到這個singletonFactories中, 繼續執行發現A例項依賴B例項,於是在建立B例項,接著又發現B例項依賴A例項,於是從singletonFactories取出A例項完成裝配,再將B返回給A,完成A的裝配


    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");
            }

            // todo  重點再來看這個 addSingleFactory
            // todo  將原始物件new出來之後放到了  這個方法中的map中
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }

        // Initialize the bean instance.
        Object exposedObject = bean; // todo 到目前為止還是原生物件
        try {
            //todo  用來填充屬性
            //設定屬性,非常重要
            populateBean(beanName, mbd, instanceWrapper);

            // todo 經過AOP處理,原生物件轉換成了代理物件,跟進去
            //執行後置處理器,aop就是在這裡完成的處理
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }

接著看populateBean(beanName, mbd, instanceWrapper);方法,這個方法很重要,就是在這個方法中進行bean屬性的裝配工作,啥意思呢? 比如現在裝配A例項,結果發現A例項中存在一個屬性是B例項,這是就得完成自動裝配的工作,原始碼如下:

如果仔細看,就會發現兩個事:

第一: 如果不出意外,就會出現兩次後置處理器的回撥,第一後置處理器的回撥是判斷當前的bean中是否存在需要裝配的屬性,而第二波後置處理器的回撥就是實打實的去完成裝配的動作

第二: 下面的第一個處理器其實就是spring啟動過程中第一個回撥的處理器,只不過呼叫了這個處理器的不同的方法postProcessAfterInstantiation(),預設返回ture表示按照正常的流程裝配物件的屬性,返回false,表示不會繼續裝配物件中的任何屬性

而我們則繼續關注下面方法中的第二個後置處理器的,看看Spring是如何完成屬性的自動裝配的,關於這部分的跟蹤,我寫在下面程式碼的後面

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
        if (bw == null) {
            if (mbd.hasPropertyValues()) {
                throw new BeanCreationException(
                        mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
            }
            else {
                // Skip property population phase for null instance.
                return;
            }
        }

        // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
        // state of the bean before properties are set. This can be used, for example,
        // to support styles of field injection.
        boolean continueWithPropertyPopulation = true;

        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    //todo 進行了強轉, InstantiationAwareBeanPostProcessor這個介面前面說過
                    // todo 只要是通過這個介面返回出來的bean Spring不在管這個bean,不給他裝配任何屬性
                    //todo 當前這裡沒有用它這個變態的特性
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    // todo postProcessAfterInstantiation()預設是返回true, 加上! 表示false
                    if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                        continueWithPropertyPopulation = false;
                        break;
                    }
                }
            }
        }

        if (!continueWithPropertyPopulation) {
            return;
        }
        // todo Spring內部可以對BeanDefinition進行設定值, 參照自定義的 BeanFactory中獲取到BeanDefinition.getPropertyValue().addXXX();
        PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

        // todo 判斷當前bean的解析模型是 byName 還是 byType
        // todo 再次驗證了:::   當程式設計師直接使用@Autowired註解時, 既不是ByName 也不是ByType, 而是No
        if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
            MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
            // Add property values based on autowire by name if applicable.
            if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
                autowireByName(beanName, mbd, bw, newPvs);
            }
            // Add property values based on autowire by type if applicable.
            if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
                autowireByType(beanName, mbd, bw, newPvs);
            }
            pvs = newPvs;
        }

        boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
        boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

        if (hasInstAwareBpps || needsDepCheck) {
            if (pvs == null) {
                pvs = mbd.getPropertyValues();
            }
            //todo 獲取出物件的所有set get方法,現在是有一個 getClass()方法,因為繼承了Object, 沒什麼其他卵用
            PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
            if (hasInstAwareBpps) {

                for (BeanPostProcessor bp : getBeanPostProcessors()) {
                    if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    
                        pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                        if (pvs == null) {
                            return;
                        }
                    }
                }
            }
            if (needsDepCheck) {
                checkDependencies(beanName, mbd, filteredPds, pvs);
            }
        }

        if (pvs != null) {
            applyPropertyValues(beanName, mbd, bw, pvs);
        }
    }

好,繼續跟進pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(),,看看spring如何完成屬性的自動裝配,當然,還是那句話,如果我們直接跟進去這個方法進入的是InstantiationAwareBeanPostProcessor抽象介面抽象方法,而我們關注的是它的實現類AutowiredAnnotationBeanDefinitionPostProcessor的實現,打上斷點依次跟進

    @Override
    public PropertyValues postProcessPropertyValues(
            PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {

        InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
        try {
            // todo 跟進來, 目的是  為 beanName 填充上屬性 bean
            metadata.inject(bean, beanName, pvs);

跟進

metadata.inject(bean, beanName, pvs);

原始碼如下:

可以這樣理解,在下面的方法中遍歷當前物件中所有可能需要依賴注入的屬性欄位

    public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
        // todo 這裡的  InjectedElement 表示單個的需要注入的元素物件
        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);
                }
                //todo 跟進  AutowiredAnnotationBeanPostProcessor 對這個方法的實現, 在600多行處
                element.inject(target, beanName, pvs);
            }
        }
    }

跟進這個inject() 我是手動刪除了這個方法中其他的很多判斷,僅僅儲存下來了下面我們關注的邏輯,邏輯很清楚,上面的程式碼中不是在遍歷所有需要自動裝配的field嗎?如果找到了的話,就得完成自動裝配,自動裝配什麼呢? 其實就是自動裝配上當前物件依賴的其他的物件而已,因為我們使用的後置處理器是AutowireAnnotationBeanPostProcessor通過下面的程式碼就能得出結論就是@Autowired預設情況下是通過反射實現的自動裝配

    // todo 來到這裡
        @Override
        protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
            Field field = (Field) this.member;
            Object value;
            value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
            if (value != null) {
                ReflectionUtils.makeAccessible(field);
                field.set(bean, value);
            }
        }
    }

我們一路往下跟進resolveDependency()我們關注這個方法如下程式碼:

if (instanceCandidate instanceof Class) {// todo !!!!!當執行到這行程式碼時, myService還沒有被例項化(singletonObjects中沒有) 執行完這一個行程式碼之後, IndexDao1完成了對myService的裝配
        instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
    }

跟進這個resolveCandidate()原始碼如下:

很直接發現,出現的遞迴的現象,這其實解析清楚了Spring是如何完成屬性注入的,就是隻不過前前後後很多介面很多類,會擾亂這個閱讀的過程

public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
        throws BeansException {
    // todo 從bean工廠的獲取,  beanName = myService   requiredType = com.changwu...OrderService2 , 跟進去這個方法, 他呼叫了AbstractBeanFactory中的getBean(){ doGetBean();}
    return beanFactory.getBean(beanName);
}

完成裝配後,其實現在的物件依然是原生的java物件 回到AbstractAutowireCapableBeanFactory中的initializeBean()方法,原始碼如下, 看了下面的程式碼就是知道了為什麼applyBeanPostProcessorsBeforeInitializationinit()applyBeanPostProcessorsAfterInitialization()之間的呼叫順序了

還有最後一個祕密需要揭開: Spring的AOP不是產生了代理物件? 那什麼時候完成的代理呢?畢竟從我開始寫這篇文章到最後都沒有看到,其實AOP的實現就在下面的程式碼中

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
    if (System.getSecurityManager() != null) {
        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
            invokeAwareMethods(beanName, bean);
            return null;
        }, getAccessControlContext());
    }
    else {
        invokeAwareMethods(beanName, bean);
    }

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        //todo 執行全部的後置處理器的 Before方法
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    try {
        // todo 執行所有的init方法
        invokeInitMethods(beanName, wrappedBean, mbd);
    }
    catch (Throwable ex) {
        throw new BeanCreationException(
                (mbd != null ? mbd.getResourceDescription() : null),
                beanName, "Invocation of init method failed", ex);
    }
    if (mbd == null || !mbd.isSynthetic()) {
        // todo 執行所有的後置處理器的 after方法
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }

    return wrappedBean;
}

我們在前面知道當遇到這個AbstractAutoProxyCreator時,回撥它的before()方法時,僅僅是標記哪些物件需要進行增強哪些物件不需增強,而沒有立即生成代理物件

現在我們關注這行程式碼wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); ,生成代理物件的邏輯就在這裡面

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (!this.earlyProxyReferences.contains(cacheKey)) {
            // todo 進入
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

看這個方法wrapIfNecessary(bean, beanName, cacheKey);最終會進入這個實現中

大家可以看到Spring為bean生成了代理物件,預設會先檢查被代理的物件有沒有實現介面,如果實現了介面,就是用jdk動態代理,否則就看看有沒有cglib的相關依賴,如果存在的相關依賴而沒有實現介面,就會使用cglib的代理模式

另外,補充通過編碼的方式控制 下面的if條件

  • config.isOptimize() -> 可以通過XMl配置, 預設false
  • config.isProxyTargetClass() -> @EnableAspectjAutoPeoxy(true) 預設也是false
@SuppressWarnings("serial")
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {

    if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
        Class<?> targetClass = config.getTargetClass();
        if (targetClass == null) {
            throw new AopConfigException("TargetSource cannot determine target class: " +
                    "Either an interface or a target is required for proxy creation.");
        }
        if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            //todo 目標物件是一個介面, 同樣是使用jdk的動態代理
            return new JdkDynamicAopProxy(config);
        }
        return new ObjenesisCglibAopProxy(config);
    }
    else {
        // todo 所以預設使用的是 jdk的動態代理
        return new JdkDynamicAopProxy(config);
    }
}