spring源碼分析四(從refresh方法說起)

本篇文章開始,我們就進(jìn)入了spring的源碼步驟分析模塊,前幾篇文章,我已經(jīng)說明了,我指定了配置文件,然后通過ClassPathXmlApplicationContext讀取配置,我們今天分析的主要邏輯是
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
文件的方式來分析源碼的,這樣,比較好梳理,廢話不多說,我們直接進(jìn)入今天的主題

public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
        this(new String[] {configLocation}, true, null);
    }

public ClassPathXmlApplicationContext(
            String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
            throws BeansException {

        super(parent);
        setConfigLocations(configLocations);
        if (refresh) {
            refresh();
        }
    }

以上流程都比較簡(jiǎn)單,我們就直接調(diào)過了,我們要重點(diǎn)關(guān)注的就是從refresh方法開始,我之前一直很好奇,為什么spring要定義這個(gè)名稱,
refresh,刷新,不應(yīng)該是初始化或者什么之類的嘛,且聽我慢慢道來,其中緣由

@Override
    public void refresh() throws BeansException, IllegalStateException {
        //使用synchronized作為同步鎖,防止第一個(gè)容器過程么有初始化成功,第二個(gè)有進(jìn)來了
        synchronized (this.startupShutdownMonitor) {
            //預(yù)刷新步驟,記錄初始化時(shí)間,容器的狀態(tài),將active設(shè)置為true,closed設(shè)置為false
            prepareRefresh();

            // 通過obtainFreshBeanFactory獲取一個(gè)bean工廠
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            .......

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        //刷新bean工廠的方法
        refreshBeanFactory();
        //獲取bean工廠
        return getBeanFactory();
    }

#AbstractRefreshableApplicationContext類下面
@Override
    protected final void refreshBeanFactory() throws BeansException {
        //查看當(dāng)前bean工廠是否已經(jīng)存在,如果存在,就銷毀當(dāng)前所有的容器中的bean,并將當(dāng)前的beanFactory賦值為null,序列化id賦值為null
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
            //1.1創(chuàng)建DefaultListableBeanFactory對(duì)象
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            //設(shè)置序列化,就是設(shè)置一個(gè)唯一的序列化id,里面存放的就是當(dāng)前對(duì)象在內(nèi)存中的地址類
            beanFactory.setSerializationId(getId());
            //1.2是否允許bean覆蓋,是否允許自動(dòng)處理循環(huán)引用
            customizeBeanFactory(beanFactory);
            //1.3加載bean定義
            loadBeanDefinitions(beanFactory);
            synchronized (this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }

1.1:
創(chuàng)建一個(gè)bean工廠對(duì)象如果實(shí)現(xiàn)了ConfigurableApplicationContext,則返回父上下文的內(nèi)部bean工廠。否則帜矾,返回父上下文本身
比較簡(jiǎn)單,就不貼具體的代碼了
DefaultListableBeanFactory beanFactory = createBeanFactory();

1.2

customizeBeanFactory(beanFactory);
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
        //設(shè)置是否允許bean覆蓋,默認(rèn)為true
        if (this.allowBeanDefinitionOverriding != null) {
            beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
        }
        //設(shè)置是否允許自動(dòng)嘗試處理bean之間的循環(huán)引用,默認(rèn)值為true
        if (this.allowCircularReferences != null) {
            beanFactory.setAllowCircularReferences(this.allowCircularReferences);
        }
    }

允許bean覆蓋的意思是指,spring不允許同一個(gè)配置文件中,出現(xiàn)配置的bean名稱相同,但是spring是允許不同的配置文件中的命名相同的
這回導(dǎo)致一個(gè)比較嚴(yán)重的問題,當(dāng)出現(xiàn)同名的bean之后,spring不會(huì)報(bào)錯(cuò),而是會(huì)直接將之前的創(chuàng)建好的bean給覆蓋掉的,我們來演示下這個(gè)步驟
我定義了兩個(gè)配置文件,分別配置不同的屬性值,配置完成后,我們運(yùn)行下,看看結(jié)果

application-hellospring.xml
 <bean id="helloSpring" class="com.ryx.xiaoxin_distribute.spring.springIocAndAop.IOC.test1.HelloSpringImpl">
         <property name="name" value="張三"/>
 </bean>
application-hellospring1.xml
 <bean id="helloSpring" class="com.ryx.xiaoxin_distribute.spring.springIocAndAop.IOC.test1.HelloSpringImpl">
         <property name="name" value="李四"/>
 </bean>

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:application-hellospring.xml","classpath:application-hellospring1.xml");
先加載HelloSring,在加載HelloSpring1
最終會(huì)發(fā)現(xiàn)同名的時(shí)候,spring在給bean的屬性賦值的時(shí)候,會(huì)將前面賦值的屬性值覆蓋掉,怎嘛處理那,咱們這個(gè)參數(shù)就派上用場(chǎng)了
我們會(huì)看到spring定義的refresh是一個(gè)public的,也就是說我們可以調(diào)用的,那就是說,如果我們?cè)谌萜骷虞d完畢后,就可以手動(dòng)對(duì)allowBeanDefinitionOverriding
這個(gè)屬性執(zhí)行賦值操作,然后在調(diào)用refresh方法,我們?cè)囈辉?br> 修改為如下方式

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:application-hellospring.xml","classpath:application-hellospring1.xml");

        //是否允許bean覆蓋
        ((ClassPathXmlApplicationContext) applicationContext).setAllowBeanDefinitionOverriding(false);

        ((ClassPathXmlApplicationContext) applicationContext).refresh();
        System.out.println("applicationContext啟動(dòng)了....");

        // 從上下文中獲取bean
        HelloSpring helloSpring1 =  applicationContext.getBean(HelloSpringImpl.class);

        System.out.println(helloSpring1.sayHello());

再次運(yùn)行,就會(huì)報(bào)錯(cuò),源碼這里會(huì)有判斷,我們?cè)O(shè)置為false,就會(huì)直接在這里拋出異常
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
說道這里,順便說下,前面提到的一個(gè)讓我不解的問題,就是spring關(guān)于將初始化方法定義為refresh的用意,是說,我們可以無數(shù)遍的手動(dòng)
刷新這個(gè)容器,修改完一些默認(rèn)參數(shù)后,可以調(diào)用refresh方法啦!

1.3
接下來分析1.3步驟,加載bean定義
loadBeanDefinitions(beanFactory);

AbstractXmlApplicationContext
@Override
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        // 創(chuàng)建一個(gè)XmlBeanDefinitionReader對(duì)象
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

        //設(shè)置一些變量屬性
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

        //初始化bean閱讀器
        initBeanDefinitionReader(beanDefinitionReader);
        //加載bean定義
        loadBeanDefinitions(beanDefinitionReader);
    }

loadBeanDefinitions(beanDefinitionReader),加載和注冊(cè)bean的定義

我們可以看到有兩個(gè)方法可以獲取需要加載的bean,第一個(gè)是通過resources,第二個(gè)是通過配置路徑,這兩個(gè)都是可以
獲取bean的配置文件的,不過需要注意的是如果需要通過resources加載bean的話,需要我們自己繼承ClassPathXmlApplicationContext,后自己實(shí)現(xiàn)
才能加載以如下的方式執(zhí)行加載

public class ResourceContext extends ClassPathXmlApplicationContext {

    @Override
    protected Resource[] getConfigResources() {
        final ArrayList<Resource> objects = new ArrayList<Resource>(){{
            add(new ClassPathResource("application-hellospring.xml"));
            add(new ClassPathResource("application-hellospring1.xml"));
        }};
        return objects.toArray(new Resource[0]);
    }
}

ApplicationContext applicationContext = new ResourceContext();
        ((ResourceContext) applicationContext).refresh();

這兩個(gè)方法我們選擇一個(gè)吧,我們就分析 getConfigLocations吧getConfigResources就不做分析了.
因?yàn)榈讓诱{(diào)用都是loadBeanDefinitions(resource)這個(gè)方法

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
        Resource[] configResources = getConfigResources();
        if (configResources != null) {
            //重點(diǎn)方法,重點(diǎn)方法,重點(diǎn)方法
            reader.loadBeanDefinitions(configResources);
        }
        //獲取配置路徑數(shù)組,還記得我們?cè)趩?dòng)的時(shí)候的寫法嗎,getConfigLocations會(huì)獲取到一下的兩個(gè)配置
        //new ClassPathXmlApplicationContext("classpath:application-hellospring.xml","classpath:application-hellospring1.xml");
        //這里有一點(diǎn)需要注意下,如果getConfigLocations獲取不到,就回去默認(rèn)路徑下找配置文件,所以當(dāng)我們將配置文件配置在WEB-INF下的時(shí)候,
        //spring是會(huì)默認(rèn)取加載的,前提是,我們不手動(dòng)配置.默認(rèn)加載的位置是/WEB-INF/applicationContext.xml
        String[] configLocations = getConfigLocations();
        if (configLocations != null) {
            reader.loadBeanDefinitions(configLocations);
        }
    }
#reader.loadBeanDefinitions(configLocations);
AbstractBeanDefinitionReader類
@Override
    public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
        //為空,直接跑出異常
        Assert.notNull(locations, "Location array must not be null");
        //初始化變量
        int count = 0;
        //循環(huán)加載bean定義
        for (String location : locations) {
            count += loadBeanDefinitions(location);
        }
        return count;
    }

@Override
    public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
        return loadBeanDefinitions(location, null);
    }

    public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
            //獲取資源加載器對(duì)象
            ResourceLoader resourceLoader = getResourceLoader();
            //如果為空,拋出異常
            if (resourceLoader == null) {
                throw new BeanDefinitionStoreException(
                        "Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
            }

            if (resourceLoader instanceof ResourcePatternResolver) {
                // Resource pattern matching available.
                try {
                    //從配置文件中獲取資源對(duì)象數(shù)組
                    Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
                    //加載bean定義方法,發(fā)現(xiàn)沒有,這里又去調(diào)用了,饒了一大圈,最終還是通過resources去加載的,所以location的方式
                    多走了邏輯,如果使用resources加載bean定義的話,少走一些彎路,哈哈,

                    //if (configResources != null) {
                    //          reader.loadBeanDefinitions(configResources);
                    //      }

                    //重點(diǎn)方法
                    int count = loadBeanDefinitions(resources);
                    //資源加載完后,將資源添加到actualResources實(shí)際資源集合中,else里面都是一樣的,就跳過了
                    if (actualResources != null) {
                        Collections.addAll(actualResources, resources);
                    }
                    if (logger.isTraceEnabled()) {
                        logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
                    }
                    return count;
                }
                catch (IOException ex) {
                    throw new BeanDefinitionStoreException(
                            "Could not resolve bean definition resource pattern [" + location + "]", ex);
                }
            }
            else {.
                Resource resource = resourceLoader.getResource(location);
                int count = loadBeanDefinitions(resource);
                if (actualResources != null) {
                    actualResources.add(resource);
                }
                if (logger.isTraceEnabled()) {
                    logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");
                }
                return count;
            }
        }

通過以上代碼的分析,我們最終發(fā)現(xiàn),真正加載bean定義的方法是loadBeanDefinitions(resources);,一起來看看

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
        Assert.notNull(encodedResource, "EncodedResource must not be null");
        if (logger.isTraceEnabled()) {
            logger.trace("Loading XML bean definitions from " + encodedResource);
        }
        //創(chuàng)建一個(gè)set集合存放當(dāng)前資源,并將當(dāng)前資源添加到集合中
        Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
        if (currentResources == null) {
            currentResources = new HashSet<>(4);
            this.resourcesCurrentlyBeingLoaded.set(currentResources);
        }
        //如果當(dāng)前資源已經(jīng)在集合中,則拋出異常,說明當(dāng)前資源已經(jīng)加載過,并放入到了currentResources
        if (!currentResources.add(encodedResource)) {
            throw new BeanDefinitionStoreException(
                    "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
        }
        try {
            //獲取資源的輸入流
            InputStream inputStream = encodedResource.getResource().getInputStream();
            try {
                InputSource inputSource = new InputSource(inputStream);
                if (encodedResource.getEncoding() != null) {
                    inputSource.setEncoding(encodedResource.getEncoding());
                }
                //最最重要的方法出現(xiàn),就在doLoadBeanDefinitions中,這個(gè)是真正做事情的方法啊,
                return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
            }
            finally {
                inputStream.close();
            }
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException(
                    "IOException parsing XML document from " + encodedResource.getResource(), ex);
        }
        finally {
            currentResources.remove(encodedResource);
            if (currentResources.isEmpty()) {
                this.resourcesCurrentlyBeingLoaded.remove();
            }
        }
    }

總的來說,上述方法比較簡(jiǎn)單,將我們需要加載的資源放入到當(dāng)前資源集合中,如果資源已經(jīng)存在,再次添加,直接拋出異常,然后獲取資源的流
通過doLoadBeanDefinitions開始搞事情,經(jīng)過了如此多的步驟,才慢慢接近真相,后面咱們會(huì)發(fā)現(xiàn),spring中真正做事情的方式名稱都會(huì)定義為
do前綴,只要看到了這個(gè)單詞,那你離真正的核心代碼就不遠(yuǎn)了,我們繼續(xù)往下

doLoadBeanDefinitions(inputSource, encodedResource.getResource());

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
            throws BeanDefinitionStoreException {

        try {
            //將資源對(duì)象轉(zhuǎn)化為DOM對(duì)象,DOM解析是將XML文件全部載入到內(nèi)存锌仅,組裝成一顆DOM樹弛秋,然后通過節(jié)點(diǎn)以及節(jié)點(diǎn)之間的關(guān)系來解析XML文件
            Document doc = doLoadDocument(inputSource, resource);
            //注冊(cè)bean定義
            int count = registerBeanDefinitions(doc, resource);
            if (logger.isDebugEnabled()) {
                logger.debug("Loaded " + count + " bean definitions from " + resource);
            }
            return count;
        }
        .......

    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        //定義bean定義閱讀器
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        //獲取bean定義之前的數(shù)量
        int countBefore = getRegistry().getBeanDefinitionCount();
        //注冊(cè)registerBeanDefinitions對(duì)象
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        return getRegistry().getBeanDefinitionCount() - countBefore;
    }

    @Override
        public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
            this.readerContext = readerContext;
            doRegisterBeanDefinitions(doc.getDocumentElement());
        }

  protected void doRegisterBeanDefinitions(Element root) {
        //這段代碼也沒有太看懂,大致就是說處理嵌套bean,還有檢查xml文件是否匹配,也沒能太搞明白
        BeanDefinitionParserDelegate parent = this.delegate;
        this.delegate = createDelegate(getReaderContext(), root, parent);

        if (this.delegate.isDefaultNamespace(root)) {
            String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
            if (StringUtils.hasText(profileSpec)) {
                String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
                        profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
                // We cannot use Profiles.of(...) since profile expressions are not supported
                // in XML config. See SPR-12458 for details.
                if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                                "] not matching: " + getReaderContext().getResource());
                    }
                    return;
                }
            }
        }

        //解析xml文件之前的處理,這是spring提供給我們的讓我們自己自定義的方法,如果我們?cè)诩虞dxml文件之前,需要自定義類型,
        //就繼承DefaultBeanDefinitionDocumentReader類就可以執(zhí)行擴(kuò)展
        preProcessXml(root);
        //解析bean定義
        parseBeanDefinitions(root, this.delegate);
        //xml定義完之后自定義處理邏輯,如果需要的話
        postProcessXml(root);

        this.delegate = parent;
    }

    解析配置文件中的內(nèi)容
    parseBeanDefinitions(root, this.delegate);

    以下方法邏輯就是循環(huán)解析節(jié)點(diǎn),執(zhí)行結(jié)點(diǎn)解析
    protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
            if (delegate.isDefaultNamespace(root)) {
                NodeList nl = root.getChildNodes();
                for (int i = 0; i < nl.getLength(); i++) {
                    Node node = nl.item(i);
                    if (node instanceof Element) {
                        Element ele = (Element) node;
                        if (delegate.isDefaultNamespace(ele)) {
                            parseDefaultElement(ele, delegate);
                        }
                        else {
                            delegate.parseCustomElement(ele);
                        }
                    }
                }
            }
            else {
                delegate.parseCustomElement(root);
            }
        }

        private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
                //解析import標(biāo)簽
                if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
                    importBeanDefinitionResource(ele);
                }
                //解析ALIAS標(biāo)簽
                else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
                    processAliasRegistration(ele);
                }
                //解析bean標(biāo)簽
                else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
                    processBeanDefinition(ele, delegate);
                }
                else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
                    // recurse
                    doRegisterBeanDefinitions(ele);
                }
            }

我們選一個(gè)平時(shí)比較熟悉的processBeanDefinition來看下代碼,如果你堅(jiān)持不懈的看到了這里恭喜你,你馬上就撥開云霧見天日了

DefaultBeanDefinitionDocumentReader

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        //獲取bean定義會(huì)話持有者
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try {
                //注冊(cè)最終的實(shí)例
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
            }
            catch (BeanDefinitionStoreException ex) {
                getReaderContext().error("Failed to register bean definition with name '" +
                        bdHolder.getBeanName() + "'", ele, ex);
            }
            // 發(fā)送注冊(cè)事件
            getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }
    }

#BeanDefinitionReaderUtils.registerBeanDefinition
#BeanDefinitionReaderUtils
 public static void registerBeanDefinition(
            BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
            throws BeanDefinitionStoreException {

        // 以bean的當(dāng)前名稱注冊(cè)bean
        String beanName = definitionHolder.getBeanName();
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

        // 如果bean存在別名,再將別名注冊(cè)進(jìn)去
        String[] aliases = definitionHolder.getAliases();
        if (aliases != null) {
            for (String alias : aliases) {
                registry.registerAlias(beanName, alias);
            }
        }
    }

我們看一下正常注冊(cè)的bean名稱的邏輯

DefaultListableBeanFactory

@Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {
        //校驗(yàn)bean名稱和bean定義
        Assert.hasText(beanName, "Bean name must not be empty");
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");

        //對(duì)beanDefinition執(zhí)行校驗(yàn)
        if (beanDefinition instanceof AbstractBeanDefinition) {
            try {
                ((AbstractBeanDefinition) beanDefinition).validate();
            }
            catch (BeanDefinitionValidationException ex) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Validation of bean definition failed", ex);
            }
        }

        //beanDefinitionMap中獲取對(duì)應(yīng)的bean名稱是否存在BeanDefinition,如果存在,校驗(yàn)不同的配置文件中定義的同名bean是否可以覆蓋
        //如果我們手動(dòng)定義為false,這里就會(huì)拋出異常,并將當(dāng)前的bean更新到beanDefinitionMap
        BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
        if (existingDefinition != null) {
            if (!isAllowBeanDefinitionOverriding()) {
                throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
            }

            this.beanDefinitionMap.put(beanName, beanDefinition);
        }
        else {
            //bean是否已經(jīng)被至少創(chuàng)建過一次,如果被創(chuàng)建過,及執(zhí)行更新邏輯
            if (hasBeanCreationStarted()) {
                // Cannot modify startup-time collection elements anymore (for stable iteration)
                synchronized (this.beanDefinitionMap) {
                    //更新當(dāng)前bean對(duì)應(yīng)的beanDefinition到map中
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                    //將需要更新的beanDefinitionNames放入集合中
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                    if (this.manualSingletonNames.contains(beanName)) {
                        Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
                        updatedSingletons.remove(beanName);
                        this.manualSingletonNames = updatedSingletons;
                    }
                }
            }
            else {
                // 說明沒有被創(chuàng)建過,將bean名稱作為key,beanDefinition作為value,存入map中
                this.beanDefinitionMap.put(beanName, beanDefinition);
                //將bean的名稱存入beanDefinitionNames集合中
                this.beanDefinitionNames.add(beanName);
                this.manualSingletonNames.remove(beanName);
            }
            this.frozenBeanDefinitionNames = null;
        }

        //如果存在不同配置文件,同樣的bean名稱,則執(zhí)行重置操作用于更新,所以當(dāng)我們將不同的配置文件定義同一個(gè)bean名稱的時(shí)候
        //會(huì)在這里執(zhí)行重置,也就是替換操作,最后只留最后一次注冊(cè)的bean
        if (existingDefinition != null || containsSingleton(beanName)) {
            resetBeanDefinition(beanName);
        }
    }

走到這里,我們的bean就注冊(cè)完成了,最終是就是將注冊(cè)的bean放入map集合中
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
最終的結(jié)果就是如下圖所示


image.png

這樣,我們我們就獲得了bean工廠對(duì)象,里面存儲(chǔ)了,已bean名稱為key,beanDefiition為value的map集合中
beanDefiition中存儲(chǔ)了class路徑等等信息
終于分析完了第一個(gè)模塊,源碼分析還遠(yuǎn)沒有結(jié)束,繼續(xù)加油!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末紧卒,一起剝皮案震驚了整個(gè)濱河市帝际,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌传睹,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,729評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件岸晦,死亡現(xiàn)場(chǎng)離奇詭異欧啤,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)启上,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門邢隧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人冈在,你說我怎么就攤上這事倒慧。” “怎么了包券?”我有些...
    開封第一講書人閱讀 169,461評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵纫谅,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我溅固,道長(zhǎng)付秕,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,135評(píng)論 1 300
  • 正文 為了忘掉前任侍郭,我火速辦了婚禮询吴,結(jié)果婚禮上掠河,老公的妹妹穿的比我還像新娘。我一直安慰自己猛计,他們只是感情好唠摹,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,130評(píng)論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著有滑,像睡著了一般跃闹。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上毛好,一...
    開封第一講書人閱讀 52,736評(píng)論 1 312
  • 那天望艺,我揣著相機(jī)與錄音,去河邊找鬼肌访。 笑死找默,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的吼驶。 我是一名探鬼主播惩激,決...
    沈念sama閱讀 41,179評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼蟹演!你這毒婦竟也來了风钻?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,124評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤酒请,失蹤者是張志新(化名)和其女友劉穎骡技,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體羞反,經(jīng)...
    沈念sama閱讀 46,657評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡布朦,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,723評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了昼窗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片是趴。...
    茶點(diǎn)故事閱讀 40,872評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖澄惊,靈堂內(nèi)的尸體忽然破棺而出唆途,到底是詐尸還是另有隱情,我是刑警寧澤掸驱,帶...
    沈念sama閱讀 36,533評(píng)論 5 351
  • 正文 年R本政府宣布窘哈,位于F島的核電站,受9級(jí)特大地震影響亭敢,放射性物質(zhì)發(fā)生泄漏滚婉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,213評(píng)論 3 336
  • 文/蒙蒙 一帅刀、第九天 我趴在偏房一處隱蔽的房頂上張望让腹。 院中可真熱鬧远剩,春花似錦、人聲如沸骇窍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽腹纳。三九已至痢掠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間嘲恍,已是汗流浹背足画。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留佃牛,地道東北人淹辞。 一個(gè)月前我還...
    沈念sama閱讀 49,304評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像俘侠,于是被迫代替她去往敵國(guó)和親象缀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,876評(píng)論 2 361