Spring解析之finishBeanFactoryInitialization即初始化單例bean

java碼農之路 發佈 2022-03-10T16:33:53+00:00

七千字長文深刻解讀,Spirng中是如何初始化單例bean的,和面試中最常問的Spring是如何解決循環依賴?

七千字長文深刻解讀,Spirng中是如何初始化單例Bean的,和面試中最常問的Spring是如何解決循環依賴?

今天解讀Spring核心方法refresh()中最最重要的一個方法finishBeanFactoryInitialization()方法,該方法負責初始化所有的單例bean。

finishBeanFactoryInitialization()方法位於refresh()中下標為8的位置。

到目前為止,應該說是是 BeanFactory 已經創建完成,並且所有的實現了 BeanFactoryPostProcessor 接口的 Bean 都已經初始化並且其中的 postProcessBeanFactory(factory) 方法已經得到回調執行了。而且 Spring 已經「手動」註冊了一些特殊的 Bean,如 environmentsystemProperties 等。

剩下的就是初始化 singleton beans 了,大多數我們的業務中都是單例bean,就像我們寫的@Controller、@Service的類(沒有設置懶加載的)都是在這個地方初始化,以供我們使用,如果沒有設置懶加載,那麼 Spring 會在接下來初始化所有的 singleton beans。

我們先看一下refresh()的源碼,大概看下finishBeanFactoryInitialization(beanFactory)所處的位置。

@Override
        public void refresh() throws BeansException, IllegalStateException {
                synchronized (this.startupShutdownMonitor) {
                        // Prepare this context for refreshing.
                        //1、刷新前的準備
                        prepareRefresh();

                        // Tell the subclass to refresh the internal bean factory.
                        //2、將會初始化 BeanFactory、加載 Bean、註冊 Bean
                        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

                        // Prepare the bean factory for use in this context.
                        //3、設置 BeanFactory 的類加載器,添加幾個 BeanPostProcessor,手動註冊幾個特殊的 bean
                        prepareBeanFactory(beanFactory);

                        try {
                                //4、模板方法
                                // Allows post-processing of the bean factory in context subclasses.
                                postProcessBeanFactory(beanFactory);

                                // Invoke factory processors registered as beans in the context.
                                //執行BeanFactory後置處理器
                                invokeBeanFactoryPostProcessors(beanFactory);

                                // 5、Register bean processors that intercept bean creation.
                                //註冊bean後置處理器
                                registerBeanPostProcessors(beanFactory);

                                // Initialize message source for this context.
                                //國際化
                                initMessageSource();

                                // Initialize event multicaster for this context.
                                initApplicationEventMulticaster();

                                // Initialize other special beans in specific context subclasses.
                                //6、模板方法--springboot實現了這個方法
                                onRefresh();

                                // Check for listener beans and register them.
                                //7、註冊監聽器
                                registerListeners();

                                // Instantiate all remaining (non-lazy-init) singletons.
                                //8、完成bean工廠的初始化**方法重要**********************************************
                                finishBeanFactoryInitialization(beanFactory);

                                //9、 Last step: publish corresponding event.
                                finishRefresh();
                        }
1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.

我們深入finishBeanFactoryInitialization(beanFactory)中,裡面的調用線路錯綜複雜,還望讀者可以做好心理準備。

/**
         * 負責單例bean的初始化
         * Finish the initialization of this context's bean factory,
         * initializing all remaining singleton beans.
         */
        protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
                // Initialize conversion service for this context.
                //最先初始化名字為 conversionService的類,conversionService類 它用來將前端傳過來的參數和後端的 controller 方法上的參數進行綁定的時候用
                //尤其是用於非基礎類型的轉換
                if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
                                beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
                        beanFactory.setConversionService(
                                        //初始化在getBean()方法中實現
                                        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.
                // 先初始化 LoadTimeWeaverAware 類型的 Bean aop相關注:大概有個印象,以後解析aop會和它串起來。
                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.
                //freeze的單詞意思是凍結,這個時候已經開始預初始化, bean 定義解析、加載、註冊先停止
                beanFactory.freezeConfiguration();

                // Instantiate all remaining (non-lazy-init) singletons.
                //開始初始化
                beanFactory.preInstantiateSingletons();
        }
1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.

該方法是判斷bean的一系列是不是屬於某個類型的bean,如果是就調用getBean()方法,如果不是,就調用beanFactory.preInstantiateSingletons()進行初始化,我們先把getBean()放一放,重點看一看beanFactory.preInstantiateSingletons()方法。

@Override
        public void preInstantiateSingletons() throws BeansException {
                if (logger.isTraceEnabled()) {
                        logger.trace("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.
                // this.beanDefinitionNames 保存了所有的 beanNames

                List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

                // Trigger initialization of all non-lazy singleton beans...
                //// 下面這個循環,觸發所有的非懶加載的 singleton beans 的初始化操作
                for (String beanName : beanNames) {
                        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
                        // 非抽象、非懶加載的 singletons。如果配置了 'abstract = true',那是不需要初始化的
                        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
                                // 處理 FactoryBean (負責初始化工廠的bean)
                                if (isFactoryBean(beanName)) {
                                        // FactoryBean 的話,在 beanName 前面加上 『&』 符號
                                        //此處調用getBean()方法
                                        Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                                        if (bean instanceof FactoryBean) {
                                                FactoryBean<?> factory = (FactoryBean<?>) bean;
                                                // 判斷當前 FactoryBean 是否是 SmartFactoryBean 的實現
                                                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) 這個方法就可以進行初始化了
                                        getBean(beanName);
                                }
                        }
                }

                // Trigger post-initialization callback for all applicable beans...
                // 到這裡說明所有的非懶加載的 singleton beans 已經完成了初始化
                // 如果我們定義的 bean 是實現了 SmartInitializingSingleton 接口的,那麼在這裡得到回調
                //如果你想在單例bean初始化後做一些事 那就實現該接口
                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();
                                }
                        }
                }
        }
1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.66.67.68.

preInstantiateSingletons()方法的主要任務是進行初始化的,在初始化前同樣是一系列判斷,如,是否是懶加載的,是否是一個factorybean(一個特別的bean,負責工廠創建的bean),最後調用getBean()方法。

其中有個插曲是否實現了SmartInitializingSingleton接口,將接口讓你可以在bean初始化後做一些事,我們寫一個簡單的實例測試一下。

其他地方讀者看注釋了解一下即可,我們開始繼續深入getBean()方法。

getBean()方法內部調用了doGetBean()我們直接看doGetBean方法。

     
        // 我們在剖析初始化 Bean 的過程,但是 getBean 方法我們經常是用來從容器中獲取 Bean 用的,注意切換思路,
        // 已經初始化過了就從容器中直接返回,否則就先初始化再返回
        protected <T> T doGetBean(
                        String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
                        throws BeansException {

                // 獲取一個 「正統的」 beanName,處理兩種情況,一個是前面說的 FactoryBean(前面帶 『&』),
                // 一個是別名問題,因為這個方法是 getBean,獲取 Bean 用的,你要是傳一個別名進來,是完全可以的
                String beanName = transformedBeanName(name);
                // 返回值
                Object bean;

                // Eagerly check singleton cache for manually registered singletons.
                // 檢查下是不是已經創建過了
                Object sharedInstance = getSingleton(beanName);
                // 這裡說下 args ,雖然看上去一點不重要。前面我們一路進來的時候都是 getBean(beanName),
                // 所以 args 傳參其實是 null 的,但是如果 args 不為空的時候,那麼意味著調用方不是希望獲取 Bean,而是創建 Bean
                if (sharedInstance != null && args == null) {
                        if (logger.isTraceEnabled()) {
                                if (isSingletonCurrentlyInCreation(beanName)) {
                                        logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
                                                        "' that is not fully initialized yet - a consequence of a circular reference");
                                }
                                else {
                                        logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
                                }
                        }
                        // 下面這個方法:如果是普通 Bean 的話,直接返回 sharedInstance,
                        // 如果是 FactoryBean 的話,返回它創建的那個實例對象
                        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
                }

                else {
                        // Fail if we're already creating this bean instance:
                        // We're assumably within a circular reference.
                        // 創建過了此 beanName 的 prototype 類型的 bean,那麼拋異常,
                        // 往往是因為陷入了循環引用 哦,原來之前的循環依賴都是在這拋的異常,再有問題就不是無頭蒼蠅了
                        if (isPrototypeCurrentlyInCreation(beanName)) {
                                throw new BeanCurrentlyInCreationException(beanName);
                        }

                        // Check if bean definition exists in this factory.
                        // 檢查一下這個 BeanDefinition 在容器中是否存在 BeanDefinition既是包含了bean的一系列信息
                        BeanFactory parentBeanFactory = getParentBeanFactory();
                        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                                // Not found -> check parent.
                                // 如果當前容器不存在這個 BeanDefinition,試試父容器中有沒有
                                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 if (requiredType != null) {
                                        // No args -> delegate to standard getBean method.
                                        return parentBeanFactory.getBean(nameToLookup, requiredType);
                                }
                                else {
                                        return (T) parentBeanFactory.getBean(nameToLookup);
                                }
                        }

                        if (!typeCheckOnly) {
                                // typeCheckOnly 為 false,將當前 beanName 放入一個 alreadyCreated 的 Set 集合中。
                                markBeanAsCreated(beanName);
                        }

                        /*
                         * 稍稍總結一下:
                         * 到這裡的話,要準備創建 Bean 了,對於 singleton 的 Bean 來說,容器中還沒創建過此 Bean;
                         * 對於 prototype 的 Bean 來說,本來就是要創建一個新的 Bean。
                         */
                        try {
                                RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                                checkMergedBeanDefinition(mbd, beanName, args);

                                // Guarantee initialization of beans that the current bean depends on.
                                // 先初始化依賴的所有 Bean,這個很好理解。
                                // 注意,這裡的依賴指的是 depends-on 中定義的依賴
                                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.
                                // 如果是 singleton scope 的,創建 singleton 的實例
                                if (mbd.isSingleton()) {
                                        sharedInstance = getSingleton(beanName, () -> {
                                                try {
                                                        // 執行創建 Bean,詳情繼續深入
                                                        // 第三個參數 args 數組代表創建實例需要的參數,不就是給構造方法用的參數,或者是工廠 Bean 的參數嘛,不過要注意,在我們的初始化階段,args 是 null。
                                                        // 這回我們要到一個新的類了 AbstractAutowireCapableBeanFactory,看類名,AutowireCapable?類名是不是也說明了點問題了。
                                                        // 主要是為了以下場景,採用 @Autowired 註解注入屬性值:
                                                        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);
                                }
                                // 如果是 prototype scope 的,創建 prototype 的實例
                                else if (mbd.isPrototype()) {
                                        // It's a prototype -> create a new instance.
                                        Object prototypeInstance = null;
                                        try {
                                                beforePrototypeCreation(beanName);
                                                // 執行創建 Bean
                                                prototypeInstance = createBean(beanName, mbd, args);
                                        }
                                        finally {
                                                afterPrototypeCreation(beanName);
                                        }
                                        bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                                }

                                else {
                                        String scopeName = mbd.getScope();
                                        if (!StringUtils.hasLength(scopeName)) {
                                                throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
                                        }
                                        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.isTraceEnabled()) {
                                        logger.trace("Failed to convert bean '" + name + "' to required type '" +
                                                        ClassUtils.getQualifiedName(requiredType) + "'", ex);
                                }
                                throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
                        }
                }
                return (T) bean;
        }
1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.66.67.68.69.70.71.72.73.74.75.76.77.78.79.80.81.82.83.84.85.86.87.88.89.90.91.92.93.94.95.96.97.98.99.100.101.102.103.104.105.106.107.108.109.110.111.112.113.114.115.116.117.118.119.120.121.122.123.124.125.126.127.128.129.130.131.132.133.134.135.136.137.138.139.140.141.142.143.144.145.146.147.148.149.150.151.152.153.154.155.156.157.158.159.160.161.162.163.164.165.166.167.168.169.170.171.172.173.174.175.176.177.178.179.180.181.182.183.184.185.186.187.188.189.190.191.192.193.194.195.196.

具體的實例化過程在createBean()方法中,我們繼續深入createBean()方法。

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

                if (logger.isTraceEnabled()) {
                        logger.trace("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.
                // 確保 BeanDefinition 中的 Class 被加載
                Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
                if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
                        mbdToUse = new RootBeanDefinition(mbd);
                        mbdToUse.setBeanClass(resolvedClass);
                }

                // Prepare method overrides.
                // 準備方法覆寫,這裡又涉及到一個概念:MethodOverrides,它來自於 bean 定義中的 <lookup-method />
                // 和 <replaced-method />,如果讀者感興趣,回到 bean 解析的地方看看對這兩個標籤的解析。
                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.
                        // 讓 InstantiationAwareBeanPostProcessor 在這一步有機會返回代理,
                        // 在 《Spring AOP 源碼分析》那篇文章中有解釋,這裡先跳過
                        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 {
                        // 重頭戲,創建 bean
                        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
                        if (logger.isTraceEnabled()) {
                                logger.trace("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);
                }
        }
1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.

我們繼續往裡看 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) {
                        // 說明不是 FactoryBean,這裡實例化 Bean,這裡非常關鍵,細節之後再說**********
                        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.isTraceEnabled()) {
                                logger.trace("Eagerly caching bean '" + beanName +
                                                "' to allow for resolving potential circular references");
                        }
                        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
                }

                // Initialize the bean instance.
                Object exposedObject = bean;
                try {
                        // 這一步也是非常關鍵的,這一步負責屬性裝配,因為前面的實例只是實例化了,並沒有設值,這裡就是設值***************
                        populateBean(beanName, mbd, instanceWrapper);
                        // 還記得 init-method 嗎?還有 InitializingBean 接口?還有 BeanPostProcessor 接口?
                        // 這裡就是處理 bean 初始化完成後的各種回調**************
                        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;
        }
1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.66.67.68.69.70.71.72.73.74.75.76.77.78.79.80.81.82.83.84.85.86.87.88.89.90.91.92.93.94.95.96.97.98.99.100.101.102.103.

到這裡,我們已經分析完了 doCreateBean 方法,總的來說,我們已經說完了整個初始化流程。

在實例化bean後有一個特別重要的知識點,也是面試中最常問的,Spring怎麼解決循環依賴問題?核心代碼就在這個方法裡面。

循環依賴其實就是循環引用,也就是兩個或則兩個以上的bean互相持有對方,最終形成閉環。比如A依賴於B,B依賴於C,C又依賴於A。如下圖:

doCreateBean 方法有三個核心流程。

(1)createBeanInstance:實例化,其實也就是調用對象的構造方法實例化對象

(2)populateBean:填充屬性,這一步主要是多bean的依賴屬性進行填充

(3)initializeBean:調用spring xml中的init 方法。

從上面講述的單例bean初始化步驟我們可以知道,循環依賴主要發生在第一、第二步。也就是構造器循環依賴和field循環依賴。

那麼我們要解決循環引用也應該從初始化過程著手,對於單例來說,在Spring容器整個生命周期內,有且只有一個對象,所以很容易想到這個對象應該存在Cache中,Spring為了解決單例的循環依賴問題,使用了三級緩存。

我們看一下getSingleton方法。

該方法還依賴於三個map,這三個map就是三級緩存。

/** Cache of singleton objects: bean name to bean instance. */
//單例對象的cache
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

/** Cache of singleton factories: bean name to ObjectFactory. */
// 單例對象工廠的cache
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

/** Cache of early singleton objects: bean name to bean instance. */
//提前曝光的單例對象的Cache
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
1.2.3.4.5.6.7.8.9.10.11.
@Nullable
        protected Object getSingleton(String beanName, boolean allowEarlyReference) {
                // Quick check for existing instance without full singleton lock
                Object singletonObject = this.singletonObjects.get(beanName);
                
                //判斷當前單例bean是否正在創建中,也就是沒有初始化完成(比如A的構造器依賴了B對象所以得先去創建B對象
                // 或則在A的populateBean過程中依賴了B對象,得先去創建B對象,這時的A就是處於創建中的狀態。
                if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
                        singletonObject = this.earlySingletonObjects.get(beanName);
                        
                        // 是否允許從singletonFactories中通過getObject拿到對象
                        if (singletonObject == null && allowEarlyReference) {
                                synchronized (this.singletonObjects) {
                                        // Consistent creation of early reference within full singleton lock
                                        singletonObject = this.singletonObjects.get(beanName);
                                        if (singletonObject == null) {
                                                singletonObject = this.earlySingletonObjects.get(beanName);
                                                if (singletonObject == null) {
                                                        ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                                                        if (singletonFactory != null) {
                                                                singletonObject = singletonFactory.getObject();
                                                                this.earlySingletonObjects.put(beanName, singletonObject);
                                                                this.singletonFactories.remove(beanName);
                                                        }
                                                }
                                        }
                                }
                        }
                }
                return singletonObject;
        }
1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.

分析getSingleton()的整個過程,Spring首先從一級緩存singletonObjects中獲取。如果獲取不到,並且對象正在創建中,就再從二級緩存earlySingletonObjects中獲取。

如果還是獲取不到且允許singletonFactories通過getObject()獲取,就從三級緩存singletonFactory.getObject()(三級緩存)獲取,如果獲取到了則:

this.earlySingletonObjects.put(beanName, singletonObject);
                        this.singletonFactories.remove(beanName);
                        
1.2.3.

從singletonFactories中移除,並放入earlySingletonObjects中。其實也就是從三級緩存移動到了二級緩存。

從上面三級緩存的分析,我們可以知道,Spring解決循環依賴的訣竅就在於singletonFactories這個三級cache。

里就是解決循環依賴的關鍵,這段代碼發生在createBeanInstance之後,也就是說單例對象此時已經被創建出來(調用了構造器)。這個對象已經被生產出來了,雖然還不完美(還沒有進行初始化的第二步和第三步),但是已經能被人認出來了(根據對象引用能定位到堆中的對象),所以Spring此時將這個對象提前曝光出來讓大家認識,讓大家使用。

這樣做有什麼好處呢?

讓我們來分析一下「A的某個field或者setter依賴了B的實例對象,同時B的某個field或者setter依賴了A的實例對象」這種循環依賴的情況。

A首先完成了初始化的第一步,並且將自己提前曝光到singletonFactories中,此時進行初始化的第二步,發現自己依賴對象B,此時就嘗試去get(B),發現B還沒有被create,所以走create流程,B在初始化第一步的時候發現自己依賴了對象A,於是嘗試get(A),嘗試一級緩存singletonObjects(肯定沒有,因為A還沒初始化完全),嘗試二級緩存earlySingletonObjects(也沒有),嘗試三級緩存singletonFactories,由於A通過ObjectFactory將自己提前曝光了,所以B能夠通過ObjectFactory.getObject拿到A對象(雖然A還沒有初始化完全,但是總比沒有好呀),B拿到A對象後順利完成了初始化階段1、2、3,完全初始化之後將自己放入到一級緩存singletonObjects中。

此時返回A中,A此時能拿到B的對象順利完成自己的初始化階段2、3,最終A也完成了初始化,進去了一級緩存singletonObjects中,而且更加幸運的是,由於B拿到了A的對象引用,所以B現在hold住的A對象完成了初始化。

知道了這個原理時候,肯定就知道為啥Spring不能解決「A的構造方法中依賴了B的實例對象,同時B的構造方法中依賴了A的實例對象」這類問題了!因為加入singletonFactories三級緩存的前提是執行了構造器,所以構造器的循環依賴沒法解決。

接下來我們挑 doCreateBean 中的三個細節出來說說。一個是創建 Bean 實例的 createBeanInstance 方法,一個是依賴注入的 populateBean 方法,還有就是回調方法 initializeBean。

這三個方法也是極其複雜的,讀者有興趣可以繼續的深入進去。

1、 createBeanInstance 方法

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

                // 校驗一下這個類的訪問權限
                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());
                }

                Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
                if (instanceSupplier != null) {
                        return obtainFromSupplier(instanceSupplier, beanName);
                }

                if (mbd.getFactoryMethodName() != null) {
                        // 採用工廠方法實例化,不熟悉這個概念的讀者請看附錄,注意,不是 FactoryBean
                        return instantiateUsingFactoryMethod(beanName, mbd, args);
                }

                // Shortcut when re-creating the same bean...
                // 如果不是第一次創建,比如第二次創建 prototype bean。
                // 這種情況下,我們可以從第一次創建知道,採用無參構造函數,還是構造函數依賴注入 來完成實例化
                boolean resolved = false;
                boolean autowireNecessary = false;
                if (args == null) {
                        synchronized (mbd.constructorArgumentLock) {
                                if (mbd.resolvedConstructorOrFactoryMethod != null) {
                                        resolved = true;
                                        autowireNecessary = mbd.constructorArgumentsResolved;
                                }
                        }
                }
                if (resolved) {
                        if (autowireNecessary) {
                                // 構造函數依賴注入
                                return autowireConstructor(beanName, mbd, null, null);
                        }
                        else {
                                // 無參構造函數
                                return instantiateBean(beanName, mbd);
                        }
                }

                // Candidate constructors for autowiring?
                // 判斷是否採用有參構造函數
                Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
                if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
                                mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
                        // 構造函數依賴注入
                        return autowireConstructor(beanName, mbd, ctors, args);
                }

                // Preferred constructors for default construction?
                ctors = mbd.getPreferredConstructors();
                if (ctors != null) {
                        // 構造函數依賴注入
                        return autowireConstructor(beanName, mbd, ctors, null);
                }

                // No special handling: simply use no-arg constructor.
                // 調用無參構造函數
                return instantiateBean(beanName, mbd);
        }
1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.

看一下instantiateBean方法是怎麼做的。

protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {
                try {
                        Object beanInstance;
                        if (System.getSecurityManager() != null) {
                                beanInstance = AccessController.doPrivileged(
                                                (PrivilegedAction<Object>) () -> getInstantiationStrategy().instantiate(mbd, beanName, this),
                                                getAccessControlContext());
                        }
                        else {
                                // 實例化
                                beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);
                        }
                        // 包裝一下,返回
                        BeanWrapper bw = new BeanWrapperImpl(beanInstance);
                        initBeanWrapper(bw);
                        return bw;
                }
                catch (Throwable ex) {
                        throw new BeanCreationException(
                                        mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
                }
        }
1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.

我們可以看到,關鍵的地方在於:beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);

裡面是具體是實例化過程,我們進去看看。

@Override
        public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
                // Don't override the class with CGLIB if no overrides.
                // 如果不存在方法覆寫,那就使用 java 反射進行實例化,否則使用 CGLIB,
                // 方法覆寫 請參見附錄"方法注入"中對 lookup-method 和 replaced-method 的介紹
                if (!bd.hasMethodOverrides()) {
                        Constructor<?> constructorToUse;
                        synchronized (bd.constructorArgumentLock) {
                                constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
                                if (constructorToUse == null) {
                                        final Class<?> clazz = bd.getBeanClass();
                                        if (clazz.isInterface()) {
                                                throw new BeanInstantiationException(clazz, "Specified class is an interface");
                                        }
                                        try {
                                                if (System.getSecurityManager() != null) {
                                                        constructorToUse = AccessController.doPrivileged(
                                                                        (PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
                                                }
                                                else {
                                                        constructorToUse = clazz.getDeclaredConstructor();
                                                }
                                                bd.resolvedConstructorOrFactoryMethod = constructorToUse;
                                        }
                                        catch (Throwable ex) {
                                                throw new BeanInstantiationException(clazz, "No default constructor found", ex);
                                        }
                                }
                        }
                        // 利用構造方法進行實例化
                        return BeanUtils.instantiateClass(constructorToUse);
                }
                else {
                        // Must generate CGLIB subclass.
                        // 存在方法覆寫,利用 CGLIB 來完成實例化,需要依賴於 CGLIB 生成子類,這裡就不展開了。
                        // tips: 因為如果不使用 CGLIB 的話,存在 override 的情況 JDK 並沒有提供相應的實例化支持
                        return instantiateWithMethodInjection(bd, beanName, owner);
                }
        }
1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.

到這裡,我們就算實例化完成了。我們開始說怎麼進行屬性注入。

2、populateBean 方法

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.
                if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
                        for (BeanPostProcessor bp : getBeanPostProcessors()) {
                                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                                        InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                                        if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                                                return;
                                        }
                                }
                        }
                }

                // bean 實例的所有屬性都在這裡了
                PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

                int resolvedAutowireMode = mbd.getResolvedAutowireMode();
                // 通過名字找到所有屬性值,如果是 bean 依賴,先初始化依賴的 bean。記錄依賴關係
                if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
                        MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
                        // Add property values based on autowire by name if applicable.
                        if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
                                autowireByName(beanName, mbd, bw, newPvs);
                        }
                        // Add property values based on autowire by type if applicable.
                        if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
                                autowireByType(beanName, mbd, bw, newPvs);
                        }
                        pvs = newPvs;
                }

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

                PropertyDescriptor[] filteredPds = null;
                if (hasInstAwareBpps) {
                        if (pvs == null) {
                                pvs = mbd.getPropertyValues();
                        }
                        for (BeanPostProcessor bp : getBeanPostProcessors()) {
                                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                                        InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                                        PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
                                        if (pvsToUse == null) {
                                                if (filteredPds == null) {
                                                        filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
                                                }
                                                // 這裡有個非常有用的 BeanPostProcessor 進到這裡: AutowiredAnnotationBeanPostProcessor
                                                // 對採用 @Autowired、@Value 註解的依賴進行設值,這裡的內容也是非常豐富的
                                                pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                                                if (pvsToUse == null) {
                                                        return;
                                                }
                                        }
                                        pvs = pvsToUse;
                                }
                        }
                }
                if (needsDepCheck) {
                        if (filteredPds == null) {
                                filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
                        }
                        checkDependencies(beanName, mbd, filteredPds, pvs);
                }

                if (pvs != null) {
                        // 設置 bean 實例的屬性值
                        applyPropertyValues(beanName, mbd, bw, pvs);
                }
        }
1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.66.67.68.69.70.71.72.73.74.75.76.77.78.79.80.81.82.83.

屬性注入完成後,這一步其實就是處理各種回調了,這塊代碼比較簡單。

3、 initializeBean方法

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
                if (System.getSecurityManager() != null) {
                        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                                invokeAwareMethods(beanName, bean);
                                return null;
                        }, getAccessControlContext());
                }
                else {
                        // 如果 bean 實現了 BeanNameAware、BeanClassLoaderAware 或 BeanFactoryAware 接口,回調
                        invokeAwareMethods(beanName, bean);
                }

                Object wrappedBean = bean;
                if (mbd == null || !mbd.isSynthetic()) {
                        // BeanPostProcessor 的 postProcessBeforeInitialization 回調
                        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
                }

                try {
                        // 處理 bean 中定義的 init-method,
                        // 或者如果 bean 實現了 InitializingBean 接口,調用 afterPropertiesSet() 方法
                        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()) {
                        // BeanPostProcessor 的 postProcessAfterInitialization 回調
                        //BeanPostProcessor 的兩個回調都發生在這邊,只不過中間處理了 init-method
                        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
                }

                return wrappedBean;
        }
1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.

自此,Spring實例化單例非懶加載bean的過程也就完成了,這也是Spirng最最重要的方法了。在我們的日常使用Spring中,定義好各個類,然後在上面加上,@Controller,@Service,Autowired等註解,這些註解是怎麼起作用的呢?

想必大部分同學都是知其然,不知其所以然,想必通過本文,讀者心中能有一個清楚的認識。

關鍵字: