【Spring Framework】Spring中IOC容器初始化及Bean解析过程

Spring IOC设计了两个接口BeanFactory实现了容器最基本的功能,ApplicationContext应用上下文在BeanFactory的基础上增加了许多功能。

【Spring Framework】Spring中IOC容器初始化及Bean解析过程_第1张图片
ApplicationContext的类的实现
ClassPathXmlApplicationContext,FileSystemApplicactionContext:

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

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

IOC容器的启动是refresh()方法开始的。
这个启动包含BeanDefinition的Resource定位,载入和注册三个基本过程。
1)Resource定位:即BeanDefinition的资源定位,通过ResourceLoaader的Resource接口完成。
2)BeanDefinition的载入:把用户定义的Bean表示成IOC容器的数据结果BeanDefinition。
3)向IOC容器中注入这些BeanDefinition的过程:通过调用BeanDefinitionRegistry接口来完成。
这只是IOC容器初始化过程,不包括Bean依赖注入的过程。在Spring中依赖注入一般发生在应用第一次通过getBean向容器索取Bean的时候。当然也可以配置lazyinit属性决定是否懒加载bean。

1. Resource定位

Spring启动一般是通过加载Sping.xml文件启动,我们以ClassPathXmlApplicationContext为例,一般启动方式为:

public class SpringDemoMain {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        context.start();
    }
}

查看ClassPathXmlApplicationContext 的类继承结构:
【Spring Framework】Spring中IOC容器初始化及Bean解析过程_第2张图片
ClassPathXmlApplicationContext 通过继承实现ResourceLoader已经具备了读取Resource资源的能力。

ClassPathXmlApplicationContext通过以下方法初始化BeanDefinition资源调用,其中refresh()为具体BeanDefinition的载入过程:

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

		super(parent);
		// 设置载入spring.xml配置文件
		setConfigLocations(configLocations);
		if (refresh) {
			refresh();
		}
	}

2. BeanDefinition的载入和解析

refresh() 方法是定义了ApplicationContext的整个初始化过程。其具体为:

 @Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // 准备好刷新上下文。
            prepareRefresh();
            // 告诉子类刷新内部bean工厂。
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
            // 准备bean工厂,以便在此上下文中使用。
            prepareBeanFactory(beanFactory);
            try {
                // 允许在上下文子类中对bean工厂进行后处理。所有bean定义都已加载,但还没有实例化bean。这允许在特定的ApplicationContext实现中注册特殊的beanpostprocessor等。
				// 此时啥都不做
                postProcessBeanFactory(beanFactory);
                // 调用上下文中注册为bean的工厂处理器。
                invokeBeanFactoryPostProcessors(beanFactory);
                // 注册拦截bean创建的bean处理器。
                registerBeanPostProcessors(beanFactory);
                // 初始化此上下文的消息源,国际化
                initMessageSource();
                // 初始化上下文中的事件机制,时间监听机制初始化
                initApplicationEventMulticaster();
                // 初始化其他特殊的bean,目前什么都不做
                onRefresh();
                // 检查监听Bean并且将这些Bean向容器注册,ApplicationListener监听机制
                registerListeners();
                // 实例化所有的 (non-lazy-init) 单件
                finishBeanFactoryInitialization(beanFactory);
                // 发布容器事件,结束Refresh过程
                finishRefresh();
            }
            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }
                // 销毁已经创建的单例,以避免挂起资源。
                destroyBeans();
                // 重置 'active' 标志
                cancelRefresh(ex);
                throw ex;
            }
            finally {
                // 重置Spring核心中的公共内省缓存,因为我们可能再也不需要单例bean的元数据了……
                resetCommonCaches();
            }
        }
    }

prepareRefresh();是一些校验的东西
详细看:
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
跟踪obtainFreshBeanFactory()方法:

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
		// 此实现对该上下文的底层bean工厂执行实际刷新,关闭前一个bean工厂(如果有的话),并为上下文生命周期的下一阶段初始化一个新的bean工厂。
		refreshBeanFactory();
		return getBeanFactory();
}

跟踪进入AbstractRefreshableApplicationContext的refreshBeanFactory()方法:

 protected final void refreshBeanFactory() throws BeansException {
        // 已经有则销毁重启
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
            // 创建DefaultListableBeanFactory工厂
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());
            // 是否允许循环引用,是否允许覆盖Bean定义
            customizeBeanFactory(beanFactory);
            // 根据工厂创建XmlBeanDefinitionReader,并加装配置文件
            loadBeanDefinitions(beanFactory);
            synchronized (this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }

重点看loadBeanDefinitions(beanFactory);这个方法就是加载bean并解析的地方吗,更总发现loadBeanDefinitions是一个抽象方法,有多个实现:
【Spring Framework】Spring中IOC容器初始化及Bean解析过程_第3张图片
如果不知道是哪个,可以debug找出跳转的地方,这里会进入AbstractXmlApplicationContext的loadBeanDefinitions方法:

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		// Create a new XmlBeanDefinitionReader for the given BeanFactory.
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

		// Configure the bean definition reader with this context's
		// resource loading environment.
		beanDefinitionReader.setEnvironment(this.getEnvironment());
		beanDefinitionReader.setResourceLoader(this);
		beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

		// Allow a subclass to provide custom initialization of the reader,
		// then proceed with actually loading the bean definitions.
		initBeanDefinitionReader(beanDefinitionReader);
		loadBeanDefinitions(beanDefinitionReader);
	}

这里主要就是创建一个XML解析工厂(解析我们传入到ClassPathApplicationContext中的参数xml文件),然后解析,解析的具体方法是loadBeanDefinitions, 进入该方法查看:

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
		Resource[] configResources = getConfigResources();
		if (configResources != null) {
			reader.loadBeanDefinitions(configResources);
		}
		String[] configLocations = getConfigLocations();
		if (configLocations != null) {
			reader.loadBeanDefinitions(configLocations);
		}
	}

其会通过xml解析类 reader.loadBeanDefinitions(configLocations);解析配置文件,继续跟踪最终进入到解析的具体方法是AbstractBeanDefinitionReader的loadBeanDefinitions:

public int loadBeanDefinitions(String location, @Nullable Set actualResources) throws BeanDefinitionStoreException {
		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 {
				Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
				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;
		}
	}

其实这还不是最终解析XML的地方,还需要继续跟踪上述方法里的:

int count = loadBeanDefinitions(resources);

最终会进入到XmlBeanDefinitionReader类的loadBeanDefinitions方法中,:

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 currentResources = this.resourcesCurrentlyBeingLoaded.get();
		if (currentResources == null) {
			currentResources = new HashSet<>(4);
			this.resourcesCurrentlyBeingLoaded.set(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());
				}
				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();
			}
		}
	}

上述方法表示,会将xml配置文件转化为流进行解析,解析的方法是:

return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {

		try {
			Document doc = doLoadDocument(inputSource, resource);
			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);
		}
	}

上述解析过程,就是把流转化为Document对象,在对其进行解析注册bean的过程。所以把流转为Document对象的是
Document doc = doLoadDocument(inputSource, resource);这行代码,当然方面里面的具体的过程,而针对Document对象解析的方法通过
int count = registerBeanDefinitions(doc, resource);这一行代码,还得继续跟踪,查看bean对象解析过程,最终找到DefaultBeanDefinitionDocumentReader类的doRegisterBeanDefinitions方法:

protected void doRegisterBeanDefinitions(Element root) {
		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;
				}
			}
		}
		preProcessXml(root);
		parseBeanDefinitions(root, this.delegate);
		postProcessXml(root);
		this.delegate = parent;
	}

然后查看具体解析的方法parseBeanDefinitions:

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

这里就是最终解析xml中各个标签的过程。

3. BeanDefinition在IOC容器中注册

在BeanDefinition载入之后,还不能直接使用,需要IOC容器对这些数据进行注册,注册是在DefaultListableBeanFactory中,通过一个HashMap来持有载入的BeanDefinition的:

/** Map of bean definition objects, keyed by bean name. */
	private final Map beanDefinitionMap = new ConcurrentHashMap<>(256);

为什么结果会存入到上述的DefaultListableBeanFactory的beanDefinitionMap 中,通过第二步注册解析的步骤继续跟踪发现:
【Spring Framework】Spring中IOC容器初始化及Bean解析过程_第4张图片
最终添加到map集合的地方:

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 {
				((AbstractBeanDefinition) beanDefinition).validate();
			}
			catch (BeanDefinitionValidationException ex) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Validation of bean definition failed", ex);
			}
		}

		BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
		if (existingDefinition != null) {
			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 updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
					updatedDefinitions.addAll(this.beanDefinitionNames);
					updatedDefinitions.add(beanName);
					this.beanDefinitionNames = updatedDefinitions;
					if (this.manualSingletonNames.contains(beanName)) {
						Set updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
						updatedSingletons.remove(beanName);
						this.manualSingletonNames = updatedSingletons;
					}
				}
			}
			else {
				// Still in startup registration phase
				this.beanDefinitionMap.put(beanName, beanDefinition);
				this.beanDefinitionNames.add(beanName);
				this.manualSingletonNames.remove(beanName);
			}
			this.frozenBeanDefinitionNames = null;
		}

		if (existingDefinition != null || containsSingleton(beanName)) {
			resetBeanDefinition(beanName);
		}
	}

到这里BeanDefinition已经注册到IOC容器中,可以使用了。DefaultListableBeanFactory中存放了整个Bean的配置信息。

你可能感兴趣的:(spring)