Spring源码学习第四天==>初识Refresh()

Spring中AbstractApplicationContext的Refresh方法

Refresh方法可以算的上是SpringIOC容器启动的核心方法了。这几天进行了深入的学习,溯源,整理流程图。

文章内容

1.refresh下的prepareRefresh方法

2.refresh下的obtainFreshBeanFactory方法

refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			/**
			 * 前戏,做容器刷新前的准备工作
			 * 1、设置容器的启动时间
			 * 2、设置活跃状态为true
			 * 3、设置关闭状态为false
			 * 4、获取Environment对象,并加载当前系统的属性值到Environment对象中
			 * 5、准备监听器和事件的集合对象,默认为空的集合
			 */
            prepareRefresh()
		
}

 

一.prepareRefresh():如注释中表明的,这是容器刷新前的准备工作。为了提高效率,我将代码详解写进代码段的注释中。

protected void prepareRefresh() {
		// Switch to active.
		// 设置容器启动的时间==>获取当前时间作为容器的启动时间
		this.startupDate = System.currentTimeMillis();
		// 容器的关闭标志位
		this.closed.set(false);
		// 容器的激活标志位
		this.active.set(true);

		// 记录日志
		if (logger.isDebugEnabled()) {
			if (logger.isTraceEnabled()) {
				logger.trace("Refreshing " + this);
			}
			else {
				logger.debug("Refreshing " + getDisplayName());
			}
		}

		// Initialize any placeholder property sources in the context environment.
		/**
		 * 1.留给子类覆盖,初始化属性资源
		 * 2.假设:项目需要一些系统资源,那么子类重写这个方法的时候并被调用的时候,
		 * 就可以通过getEnvironment()方法,将所需要的系统环境变量名加入其中,以进行下一步的判断
		 */
		initPropertySources();

		// Validate that all properties marked as required are resolvable:
		// see ConfigurablePropertyResolver#setRequiredProperties

		/**
		 * 1.先返回当前的系统环境对象
		 * 2.验证需要的属性文件是否都已经放入环境中
		 * 3.为了验证  initPropertySources();
		 */
		getEnvironment().validateRequiredProperties();

		// Store pre-refresh ApplicationListeners...
		// 判断刷新前的应用程序监听器集合是否为空,如果为空,则将监听器添加到此集合中
		if (this.earlyApplicationListeners == null) {
			this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
		}
		else {
			// Reset local application listeners to pre-refresh state.
			// 如果不等于空,则清空集合元素对象
			this.applicationListeners.clear();
			this.applicationListeners.addAll(this.earlyApplicationListeners);
		}
		// Allow for the collection of early ApplicationEvents,
		// to be published once the multicaster is available...
		// 创建刷新前的监听事件集合
		this.earlyApplicationEvents = new LinkedHashSet<>();
	}

二.obtainFreshBeanFactory方法。这里面进行了XML文件的解析工作,将XML解析成BeanDefinition。

refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
		// Tell the subclass to refresh the internal bean factory.
		// 创建容器对象:DefaultListableBeanFactory
		// 设置BeanFactory的Id,设置一些默认值,比如是否需要解决循环依赖
		// 加载xml配置文件的属性值到当前工厂中,最重要的就是BeanDefinition
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
		
}

阅读完代码段中关于该方法的释意后,我们来进行详解一下

1.在创建BeanFacory之前,先进行了刷新工厂的操作

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
		/**
		 * 1.初始化BeanFactory
		 * 2.对XML配置文件进行读取
		 * 3.将得到的BeanFactory记录到当前的实体内
		 */
		refreshBeanFactory();
		// 返回当前实体的beanFactory属性
		return getBeanFactory();
}
2.接着来关注一下如何进行工厂刷新操作  ==>调用的是 AbstractRefreshableApplicationContext类下的方法
@Override
	protected final void refreshBeanFactory() throws BeansException {
		// 如果存在beanFactory,则销毁beanFactory
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
			/**
			 * 创建DefaultListableBeanFactory对象
 			 */
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			// 为了序列化指定id,可以从id反序列化到beanFactory对象
			beanFactory.setSerializationId(getId());
			// 定制beanFactory,设置相关属性,包括是否允许覆盖同名称的不同定义的对象以及循环依赖
			// 子类如果进行实现,那么该方法就调用子类的
			customizeBeanFactory(beanFactory);
			// 初始化documentReader,并进行XML文件读取及解析,默认命名空间的解析,自定义标签的解析
			loadBeanDefinitions(beanFactory);
			this.beanFactory = beanFactory;
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}

3.该方法中最为重要的就是loadBeanDefinitions(beanFacory)方法,这里面准备进行XML的解析操作==>调用的是AbstractXmlApplicationContext类下的方法。

  总结而言该方法主要的事情做了2个

  1)创建XmlBeanDefinitionReader对象,也就是配置文件读取对象

  2)就是引导下一步的解析操作

@Override
	protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		// Create a new XmlBeanDefinitionReader for the given BeanFactory.
		// 创建一个xml的beanDefinitionReader,并通过回调设置到beanFactory中
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

		// Configure the bean definition reader with this context's
		// resource loading environment.
		// 给reader对象设置环境对象
		beanDefinitionReader.setEnvironment(this.getEnvironment());
		// 设置资源加载器   (this==ClassPathXmlApplicationContext)
		beanDefinitionReader.setResourceLoader(this);
		// 设置实体处理器(这里的实体是指XML内的信息当成实体)
		// new ResourceEntityResolver(this) 会将 xsd文件所映射的文件位置(META-INF/spring.schemas)
		/**
		 * 1.创建了dtd解析器和xsd解析器对象赋值给==>ResourceEntityResolver对象
		 * 2.在创建解析xsd文件解析器时, 指定了要去查找的配置文件位置 "META-INF/spring.schemas"
		 * 2.将当前上下文对象作为Reader的this.resourceLoader
		 */
		beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

		// Allow a subclass to provide custom initialization of the reader,
		// then proceed with actually loading the bean definitions.
		//  初始化beanDefinitionReader对象,此处设置配置文件是否要进行验证
		initBeanDefinitionReader(beanDefinitionReader);
		// 开始完成beanDefinition的加载==>解析XML
		loadBeanDefinitions(beanDefinitionReader);
	}

4.如下方法,进行读取配置文件名称,准备进行解析配置文件名的操作

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
		// 以Resource的方式获得配置文件的资源位置
		Resource[] configResources = getConfigResources();
		if (configResources != null) {
			reader.loadBeanDefinitions(configResources);
		}
		// 以String的形式获得配置文件的位置
        //我们通常都是以字符串形式来录入配置文件名称,所以在此方法中,只会执行以下分支分段,上面的分支判断是走不通的。因为我们的Debug就是以字符串形式在走
		String[] configLocations = getConfigLocations();
		if (configLocations != null) {
			//开始加载每一个XML配置文件
			reader.loadBeanDefinitions(configLocations);
		}
	}

5.该方法是AbstractBeanDefinitionReader下的方法,我们创建的XmlBeanDefinitionReader继承与它

   该方法本质上是将String[]  配置文件名数组,进行了遍历,从而进行逐个解析

@Override
	public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
		Assert.notNull(locations, "Location array must not be null");
		int count = 0;
		for (String location : locations) {
			//遍历每一个XML配置文件,然后进行加载单个配置文件的定义信息
			count += loadBeanDefinitions(location);
		}
		return count;
	}

6.还是在AbstractBeanDefinitionReader方法中的主要操作

   1)将遍历出来的配置文件名解析为Resource[] ,因为下面内容较多,解析Resource[]的流程我们不再赘言,大致来讲,就是将一个个的配置文件名称再进行解析一边,看一下是否包含“classpath:”此类的开头结尾以进行下一步操作

   2)加载Bean的定义信息。接下来的小点就来解答一下  loadBeanDefinitions(resources);

public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
		//在创建XmlBeanDefinitionReader时,就将ClassPathXmlApplicationContext通过构造函数的方式写入了
		ResourceLoader resourceLoader = getResourceLoader();
		if (resourceLoader == null) {
			throw new BeanDefinitionStoreException(
					"Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
		}
		//AbstractApplicationContext的构造方法中进行了设置ResourcePatternResolver
		if (resourceLoader instanceof ResourcePatternResolver) {
			// Resource pattern matching available.
			try {

				/**
				 * 1.ClassPathXmlApplicationContext也是继承了ResourcePatternResolver
				 * 2.ResourcePatternResolver中的getResources()被AbstractApplicationContext重写了
				 * 3.getResources()这个方法的作用是对配置文件的前缀和后缀进行判断
				 * 					前缀: "classpath*:";
				 * 				    后缀: "war:"
				 */
				// 调用DefaultResourceLoader的getResource完成具体的Resource定位
				Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);

				//加载Bean的定义信息    解析后的resources[]
				int count = loadBeanDefinitions(resources);
				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 {
			// Can only load single resources by absolute URL.
			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;
		}
	}

7.还是属性的配方,将Resource[] ==>Resource。通过循环遍历的方式取出一个个Resource进行解析。此时我们经历了配置文件名从

   String[] ==> String ==> Resource[] ==> Resource

@Override
	public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
		Assert.notNull(resources, "Resource array must not be null");
		int count = 0;
		for (Resource resource : resources) {
			count += loadBeanDefinitions(resource);
		}
		return count;
	}

7.以下方法中   通过包含包裹着Ressource的流和Resource来进行解析配置文件的核心处理逻辑,此时的类是XmlBeanDefinitionReader

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


        // 通过属性来记录已经加载的资源
        Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();

		//将被字符集包装的文件资源名称放入本地线程变量中
        if (!currentResources.add(encodedResource)) {
            throw new BeanDefinitionStoreException(
                    "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
        }

        // 从encodedResource中获取已经封装的Resource对象并再次从Resource中获取其中的inputStream
        try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
            InputSource inputSource = new InputSource(inputStream);
            if (encodedResource.getEncoding() != null) {
                inputSource.setEncoding(encodedResource.getEncoding());
            }
            // 逻辑处理的核心步骤			(通过文件资源名称获取的流)  (文件资源的对象)
            return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
        } catch (IOException ex) {
            throw new BeanDefinitionStoreException(
                    "IOException parsing XML document from " + encodedResource.getResource(), ex);
        } finally {
            currentResources.remove(encodedResource);
            if (currentResources.isEmpty()) {
                this.resourcesCurrentlyBeingLoaded.remove();
            }
        }
    }

8.下面代码段中的重点有2个

  1)将Rsource资源解析成Document对象,相对而言,可以不仔细研究

  2)注册BeanDefinition。接下来会进行往下走。 registerBeanDefinitions(doc, resource)

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

        try {
			/**
			 * 1.doLoadDocument实现的过程中还定义了是以dtd还是xsd形式进行解析
			 * 2.此处获取xml文件的document对象,这个解析过程是由documentLoader完成的,
			 * 3.从String[] - string - Resource[] - resource,
			 * 4.最终开始将resource读取成一个document文档,根据文档的节点信息封装成一个个的BeanDefinition对象
			 */
            Document doc = doLoadDocument(inputSource, resource);
            //注册BeanDefinition定义信息
            int count = registerBeanDefinitions(doc, resource);
            if (logger.isDebugEnabled()) {
                logger.debug("Loaded " + count + " bean definitions from " + resource);
            }
            return count;
        } catch (BeanDefinitionStoreException ex) {
            throw ex;
        } catch (SAXParseException ex) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(),
                    "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
        } catch (SAXException ex) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(),
                    "XML document from " + resource + " is invalid", ex);
        } catch (ParserConfigurationException ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(),
                    "Parser configuration exception parsing XML from " + resource, ex);
        } catch (IOException ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(),
                    "IOException parsing XML document from " + resource, ex);
        } catch (Throwable ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(),
                    "Unexpected exception parsing XML document from " + resource, ex);
        }
    }

9.该方法有三个流程

  1)创建一个用来解析Document对象的处理类

  2)为了程序编译通过而维护的返回值设置

  3)解析Docemnet对象的操作。下一步往内走

  public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        // 创建一个解析document解析对象
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        //获取在这之前有的BeanDefinition
        int countBefore = getRegistry().getBeanDefinitionCount();

        // 完成具体的解析过程
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        return getRegistry().getBeanDefinitionCount() - countBefore;
    }

10.接下来的方法是DefaultBeanDefinitionDocumentReader类的方法

   1)主要的方法是倒数第三个,传入root解析出BeanDefinition

	protected void doRegisterBeanDefinitions(Element root) {
		// Any nested <beans> elements will cause recursion in this method. In
		// order to propagate and preserve <beans> default-* attributes correctly,
		// keep track of the current (parent) delegate, which may be null. Create
		// the new (child) delegate with a reference to the parent for fallback purposes,
		// then ultimately reset this.delegate back to its original (parent) reference.
		// this behavior emulates a stack of delegates without actually necessitating one.

		BeanDefinitionParserDelegate parent = this.delegate;
		//创建一个单独的解析器来进行解析
		this.delegate = createDelegate(getReaderContext(), root, parent);

		//判断是否为默认的命名空间
		if (this.delegate.isDefaultNamespace(root)) {
			/**
			 * 判断是否有PROFILE_ATTRIBUTE这个属性值
			 * 1.PROFILE_ATTRIBUTE是否包含 profile这个属性值
			 * 2.用来指定选择哪一个配置文件
			 * 3.springboot可能会有
			 */
			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;
				}
			}
		}

		//SpringMVC时讲解
		preProcessXml(root);
		//解析BeanDefinition  传入根节点,和解析器==>从跟节点解析document
		parseBeanDefinitions(root, this.delegate);
		postProcessXml(root);

		this.delegate = parent;
	}

11.判断标签属于哪种标签,以选择不同的方式来处理。本文叙述的是以<Bean>标签为代表的默认命名空间内的标签解析

   1)因为是以<Bean>标签举例,所以我们走的是parseDefaultElement(ele, delegate);方法。然后接下来我们再追以下源码。

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
		if (delegate.isDefaultNamespace(root)) {//是否是默认的命名空间
			//<beans>
			NodeList nl = root.getChildNodes();//获取第一个子节点
			for (int i = 0; i < nl.getLength(); i++) {//获取nl的长度
				//比如<beans></beans> 下的<bean></bean>等
				Node node = nl.item(i); //获取子节点下的每一个子节点==>空格换行也算
				if (node instanceof Element) {//判断该节点是否为一个元素
					Element ele = (Element) node; //将节点转为Element 元素对象
					/**
					 * 1.比如<bean><bean/>就是默认的命名空间里的元素
					 * 2.<aop:><aop:/>  <context:><context/>这些是我们额外导入的命名空间
					 * 3.这两种的解析方式是不一样==>所以要分开去进行解析
					 * 4.可以看到方法调用了解不同的处理逻辑
					 */
					if (delegate.isDefaultNamespace(ele)) {//根据当前这个元素判断是否为默认命名中间中的元素
						parseDefaultElement(ele, delegate);
					}
					else {
						//解析自定义标签
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
			delegate.parseCustomElement(root);
		}
	}

12.该方法是用来解析默认命名空间内的标签的

   1)通过这个方法,我们可以得出。默认命名空间的标签有四种

  •  <import>
  • <alias>
  • <bean>
  • <beans>
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
		//如果是<import>
		if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
			importBeanDefinitionResource(ele);
		}
		//如果是<alias>
		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
			processAliasRegistration(ele);
		}
		//如果是<bean>
		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
			processBeanDefinition(ele, delegate);
		}
		//如果是<beans>
		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
			//
			doRegisterBeanDefinitions(ele);
		}
	}

13.接下来当然是走processBeanDefinition(ele, delegate);方法了

    1)根据传入的节点对其进行解析得到beanDefinitionHolder对象。对于这个对象,代码中已经有注释了

    2)如果想要研究以下具体解析流程的话,可以在往下追。大致提下流程。先读出节点中的属性值:id,class,等等。将其包装为AbstractBeanDefinition,返回的时候为beanDefinitionHolder【当然这是下面方法再往下追的流程了】

   3)然后就是注册BeanDefinition信息BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());。接下来我们来看看

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		// beanDefinitionHolder是beanDefinition对象的封装类,
		// 封装了BeanDefinition,bean的名字和别名,用它来完成向IOC容器的注册
		// 得到这个beanDefinitionHolder就意味着
		// beanDefinition是通过BeanDefinitionParserDelegate对xml元素的信息按照spring的bean规则进行解析得到的
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// Register the final decorated instance.
				// 向ioc容器注册解析得到的beanDefinition的地方
				BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
			}
			catch (BeanDefinitionStoreException ex) {
				getReaderContext().error("Failed to register bean definition with name '" +
						bdHolder.getBeanName() + "'", ele, ex);
			}
			// Send registration event.
			// 在beanDefinition向ioc容器注册完成之后,发送消息
			getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
		}
	}

14.以下方法开启了注册BeanDefinition的入口。该类是BeanDefinitionReaderUtils

   1)追下一层的入口是registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());。我们来看看下

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

		// Register bean definition under primary name.
		// 使用beanName做唯一标识注册
		String beanName = definitionHolder.getBeanName();
		registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

		// Register aliases for bean name, if any.
		// 注册所有的别名
		String[] aliases = definitionHolder.getAliases();
		if (aliases != null) {
			for (String alias : aliases) {
				registry.registerAlias(beanName, alias);
			}
		}
	}

15.这个类是DefaultListableBeanFactory。还有印象吗?我们在第二步,刷新工厂时创建了它

  1)下面代码很长,我来粗糙的说下。这里存了2个很重要的东西到我们的BeanFactory内

  •       beanDefinitionMap。用来存放BeanDefinition 
  •      beanDefinitionNames。用来存放beanId
@Override
	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {

		Assert.hasText(beanName, "Bean name must not be empty");
		Assert.notNull(beanDefinition, "BeanDefinition must not be null");

		if (beanDefinition instanceof AbstractBeanDefinition) {
			try {
				// 注册前的最后一个校验,这里的检验不同于之前的xml文件校验,主要是对应abstractBeanDefinition属性的methodOverrides校验,
				// 检验methodOverrides是否与工厂方法并存或者methodoverrides对应的方法根本不存在
				((AbstractBeanDefinition) beanDefinition).validate();
			}
			catch (BeanDefinitionValidationException ex) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Validation of bean definition failed", ex);
			}
		}

		BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
		// 处理注册已经注册的beanName情况
		if (existingDefinition != null) {
			// 如果对应的beanName已经注册且在配置中配置了bean不允许被覆盖,则抛出异常
			if (!isAllowBeanDefinitionOverriding()) {
				throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
			}
			else if (existingDefinition.getRole() < beanDefinition.getRole()) {
				// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
				if (logger.isInfoEnabled()) {
					logger.info("Overriding user-defined bean definition for bean '" + beanName +
							"' with a framework-generated bean definition: replacing [" +
							existingDefinition + "] with [" + beanDefinition + "]");
				}
			}
			else if (!beanDefinition.equals(existingDefinition)) {
				if (logger.isDebugEnabled()) {
					logger.debug("Overriding bean definition for bean '" + beanName +
							"' with a different definition: replacing [" + existingDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			else {
				if (logger.isTraceEnabled()) {
					logger.trace("Overriding bean definition for bean '" + beanName +
							"' with an equivalent definition: replacing [" + existingDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			this.beanDefinitionMap.put(beanName, beanDefinition);
		}
		else {
			if (hasBeanCreationStarted()) {
				// Cannot modify startup-time collection elements anymore (for stable iteration)
				synchronized (this.beanDefinitionMap) {
					this.beanDefinitionMap.put(beanName, beanDefinition);
					List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
					updatedDefinitions.addAll(this.beanDefinitionNames);
					updatedDefinitions.add(beanName);
					this.beanDefinitionNames = updatedDefinitions;
					removeManualSingletonName(beanName);
				}
			}
			else {
				// Still in startup registration phase

				// 注册beanDefinition
				this.beanDefinitionMap.put(beanName, beanDefinition);
				// 记录beanName
				this.beanDefinitionNames.add(beanName);
				removeManualSingletonName(beanName);
			}
			this.frozenBeanDefinitionNames = null;
		}

		if (existingDefinition != null || containsSingleton(beanName)) {
			// 重置所有beanName对应的缓存
			resetBeanDefinition(beanName);
		}
		else if (isConfigurationFrozen()) {
			clearByTypeCache();
		}
	}

 

 

 

到这里算是对创建BeanFactory流程分支中的刷新工厂以及解析配置文件做了一定的详细解读。最后就是配上解析配置文件的流程图

 

 

 

 

 

 

 

 


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值