spring源碼分析六(Bean實例化的預(yù)處理)

今天這節(jié)內(nèi)容我們一起來研究下,spring的bean的創(chuàng)建,我們一步步看著源碼往下分析.下面的方法就會帶我們進入bean的創(chuàng)建

完成bean工廠初始化
finishBeanFactoryInitialization(beanFactory);

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        // 初始化類型轉(zhuǎn)換器,這一部分的內(nèi)容,就是說,當前端傳過來的數(shù)據(jù)類型后臺不好解析,可以通過這個實現(xiàn)這個接口來實現(xiàn)類類型轉(zhuǎn)換
        //最典型的應(yīng)用就是data轉(zhuǎn)換
        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));
        }

        //如果之前沒有任何bean后處理器(例如PropertyPlaceholderConfigurer Bean)之前進行過注冊,請注冊默認的嵌入式值解析器,
        //主要用于注釋屬性值的解析
        if (!beanFactory.hasEmbeddedValueResolver()) {
            beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
        }

        // 初始化 LoadTimeWeaverAwareBean 用于織入第三方模塊,在 class 文件載入 JVM 的時候動態(tài)織入
        String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
        for (String weaverAwareName : weaverAwareNames) {
            getBean(weaverAwareName);
        }

        //將臨時類加載器設(shè)置為null
        beanFactory.setTempClassLoader(null);

        // 在初始化單例bean的過程中,先暫停bean的注冊,解析加載等等
        beanFactory.freezeConfiguration();

        //初始化非懶加載的bean
        beanFactory.preInstantiateSingletons();
    }

其他方法都比較簡單,咱們就直接從最后一個方法分析吧,這里干貨滿滿哈
#DefaultListableBeanFactory
@Override
    public void preInstantiateSingletons() throws BeansException {
        if (logger.isTraceEnabled()) {
            logger.trace("Pre-instantiating singletons in " + this);
        }

        //將所有的bean定義名稱添加到beanNames集合中
        List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

        // 遍歷所有的費懶加載的bean
        for (String beanName : beanNames) {
            //對bean定義進行合并,比如bean中引入屬性parent這一步就是來處理這個屬性的
            RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
            //如果bean不是抽象的,不是懶加載的,并且是單例的,執(zhí)行以下步驟
            if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
                //判斷是否是工廠bean
                if (isFactoryBean(beanName)) {
                    //如果是工廠bean,調(diào)用的時候再bean的名稱前面添加前綴符號&
                    Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                    //再次判斷bean是否是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 {
                    getBean(beanName);
                }
            }
        }

        //再次遍歷beanNames,對實現(xiàn)了SmartInitializingSingleton接口的類實現(xiàn)處理,這里也就是說,他的功能類似于InitzationBean合格接口
        //在單例bean加載完成后,做一些事情
        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();
                }
            }
        }
    }

//以上的方法都比較簡單,我們總結(jié)下
1:遍歷所有的非懶加載的bean
2:對bean屬性中添加了paren的屬性執(zhí)行合并處理
3:判斷某個bean是否是工廠bean,如果是,則在bean名稱前面添加前綴&再執(zhí)行處理
4:再次遍歷bean,查看bean是否實現(xiàn)了SmartInitializingSingleton,如果實現(xiàn)該接口,在進行回調(diào)處理,類似于有點像InitzationBean這個接口

接下來,我們看這個方法中重復(fù)出現(xiàn)的一個方法,getBean,沒錯,就是他,這才是我們要研究的重點,我們一起看看這個方法
代碼比較長,我們需要一步步分析啊

AbstractBeanFactory

@Override
    public Object getBean(String name) throws BeansException {
        //主要邏輯在dogetBean中
        return doGetBean(name, null, null, false);
    }

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

            //規(guī)范bean名稱,就是說,你如果給bean起了別名,我們獲取bean的時候,也能找見,這一步就是執(zhí)行這個操作的
            final String beanName = transformedBeanName(name);
            Object bean;

            // 檢查是否已經(jīng)創(chuàng)建了一個bean實例
            Object sharedInstance = getSingleton(beanName);
            //如果args不為為null,則證明是直接根據(jù)beanName獲取bean,最終會走到getObjectForBeanInstance
            if (sharedInstance != null && args == null) {
                //1.1通過bean實例獲取bean對象
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
            }

            //如果args不為空,則執(zhí)行以下邏輯,執(zhí)行創(chuàng)建bean的邏輯
            else {
                //檢查當前這個bean是否正在創(chuàng)建,如果正在創(chuàng)建,則直接拋出異常
                if (isPrototypeCurrentlyInCreation(beanName)) {
                    throw new BeanCurrentlyInCreationException(beanName);
                }

                // 檢查容器中是否已經(jīng)存在了當前這個bean
                BeanFactory parentBeanFactory = getParentBeanFactory();
                if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                    //不存在,證明當前容器中不存在這個bean,再去父容器中查看有沒有
                    String nameToLookup = originalBeanName(name);
                    if (parentBeanFactory instanceof AbstractBeanFactory) {
                        return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                                nameToLookup, requiredType, args, typeCheckOnly);
                    }
                    else if (args != null) {
                        如果args不為null直接返回父容器的結(jié)果
                        return (T) parentBeanFactory.getBean(nameToLookup, args);
                    }
                    else if (requiredType != null) {
                        //如果指定了bean的類類型,在args不為空的情況下,直接返回bean實例
                        return parentBeanFactory.getBean(nameToLookup, requiredType);
                    }
                    else {
                        //從父容器獲取一個bean直接返回
                        return (T) parentBeanFactory.getBean(nameToLookup);
                    }
                }

                //這里的typeCheckOnly默認就是false,這里的操作是將當前bean標記為已創(chuàng)建或?qū)⒁獎?chuàng)建
                if (!typeCheckOnly) {
                    markBeanAsCreated(beanName);
                }

                try {
                    //合并bean定義一級檢查bean定義
                    final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                    checkMergedBeanDefinition(mbd, beanName, args);

                    // 獲取當前bean的依賴,就是spring的屬性depneds-on這個屬性配置了這個屬性全部放入dependsOn數(shù)組中
                    String[] dependsOn = mbd.getDependsOn();
                    if (dependsOn != null) {
                        //執(zhí)行遍歷,并檢查當前bean的依賴,如果存在循環(huán)依賴,直接拋出異常
                        //這里解釋下,在spring中,如果A依賴于B,我們使用Autowird注解將B先加載,
                        //但是有個場景,是,B和A沒有任何的依賴關(guān)系,我們還要讓B先加載那,這個depends就起到作用了
                        //也就是說,spring的bean加載是沒有指定順序的,是隨意加載,用這個來控制bean的先后加載順序
                        //如果這里,在兩個bean中都配置了相互讓對方先加載,就會直接拋出異常
                        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 {
                                //這里是個遞歸調(diào)用,去獲取依賴項這個bean
                                getBean(dep);
                            }
                            catch (NoSuchBeanDefinitionException ex) {
                                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                        "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                            }
                        }
                    }

                    //這里,我們終于走到了創(chuàng)建bean的邏輯里,這里注意下,對于spring的不同的作用于,
                    //如果是單例的,就走這個邏輯
                    if (mbd.isSingleton()) {
                        sharedInstance = getSingleton(beanName, () -> {
                            try {
                                //創(chuàng)建bean方法
                                return createBean(beanName, mbd, args);
                            }
                            catch (BeansException ex) {
                                //如果拋出異常,直接銷毀bean
                                destroySingleton(beanName);
                                throw ex;
                            }
                        });
                        //創(chuàng)建完bean之后,獲取當前bean
                        bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                    }

                    //如果當前bean的屬性是Prototype,則走這個邏輯
                    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;
                }
            }
            =====================================================================================
            // 如果requiredType不為null,并且不是指定的當前bean的實例,則通過轉(zhuǎn)化器處理,如果處理結(jié)果任然是null,直接
            //拋出異常
            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;
        }

//總結(jié)下以上步驟:
1:規(guī)范bean的名稱,因為bean有可能被起了別名,所以不管是通過原bean還是通過別名,都能訪問到
2:檢查當前bean實例是否已經(jīng)創(chuàng)建,如果創(chuàng)建了,而且args參數(shù)為null的時候,證明是獲取bean,不是創(chuàng)建bean
3:如果args不為null,就執(zhí)行創(chuàng)建bean的邏輯
4:檢查當前容器中是否存在當前的bean,子容器不存在,在區(qū)父容器中查找,找到的話,直接返回當前bean
5:將當前bean設(shè)置為已創(chuàng)建或?qū)⒁獎?chuàng)建的狀態(tài)
6:獲取bean之間的依賴關(guān)系,注意,這里指的是depends-on屬性的依賴關(guān)系,一定要記清楚,這個是對于兩個沒有關(guān)系的bean,這種依賴,是不允許相互依賴的
7:注冊依賴關(guān)系,讓被依賴項先初始化,存在相互依賴,直接拋出異常
8:對不不同的bean的作用域,執(zhí)行不同的床架bean操作,singleten,prototype,(request,session,globle-session)
9:對于requiredType不為空的,又不和當前bean實匹配,使用轉(zhuǎn)換器去處理,如果結(jié)果還是null,直接拋出異常
以上內(nèi)容比較簡答,我對getBean這個方法做了整體的分析,但是由于篇幅的限制對具體的獲取bean和創(chuàng)建bean沒有分析,獲取bean和創(chuàng)建bean我將分為兩章分別介紹!
thanks!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容