Spring源码IOC初始化

spring ioc初始化,从ApplicationContext出发,ApplicationContext的主要实现类是ClassPathXmlApplicationContext和FileSystemXmlApplicationContext,前者默认从类路径加载配置文件,后者默认从文件系统中装载配置文件。

ClassPathXmlApplicationContext有多个构造方法,我们最常用的就是通过传入字符串的构造方法。

ClassPathXmlApplicationContext 构造方法

查看该构造方法:

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

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

初始化的核心就是在这个refresh(),进入该方法,是直接跳转到了AbstractApplicationContext中的refresh()方法中,说明子类并没有重写,直接使用父类方法,在这个方法中完成了IOC容器的创建以及初始化工作。

	@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
            // STEP 1: 刷新预处理
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
            // STEP 2:
            // 		a) 创建IoC容器(DefaultListableBeanFactory)
            //		b) 加载解析XML文件(最终存储到Document对象中)
            //		c) 读取Document对象,并完成BeanDefinition的加载和注册工作
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
            // STEP 3: 对IoC容器进行一些预处理(设置一些公共属性)
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
                // STEP 4: 
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				// STEP 5: 调用BeanFactoryPostProcessor后置处理器对BeanDefinition处理
                invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				// STEP 6: 注册BeanPostProcessor后置处理器
                registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				// STEP 7: 初始化一些消息源(比如处理国际化的i18n等消息源)
                initMessageSource();

				// Initialize event multicaster for this context.
				// STEP 8: 初始化应用事件广播器
                initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				// STEP 9: 初始化一些特殊的bean
                onRefresh();

				// Check for listener beans and register them.
				// STEP 10: 注册一些监听器
                registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				// STEP 11: 实例化剩余的单例bean(非懒加载方式)
                // 注意事项:Bean的IoC、DI和AOP都是发生在此步骤
                finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				// STEP 12: 完成刷新时,需要发布对应的事件
                finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}
	}

通过AbstractApplicationContextobtainFreshBeanFactory()方法中的 refreshBeanFactory() 来完成IOC容器的
刷新。此方法是直接调用 AbstractRefreshableApplicationContext 中的重写方法 

	@Override
	protected final void refreshBeanFactory() throws BeansException {
		// 如果之前有IoC容器,则销毁
    	if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
       		// 创建IoC容器,也就是DefaultListableBeanFactory
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			beanFactory.setSerializationId(getId());
			// 设置工厂的属性:是否允许BeanDefinition覆盖和是否允许循环依赖
			customizeBeanFactory(beanFactory);
            // 调用载入BeanDefinition的方法,在当前类中只定义了抽象的loadBeanDefinitions方法,具体的实现调用子类容器
			loadBeanDefinitions(beanFactory);//钩子方法
			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory;
			}
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}

 该方法先判断是否有IOC容器,如果存在则销毁,并且关闭beanFactory.通过createBeanFactory()方法来返回一个DefaultListableBeanFactory,接下来通过loadBeanDefinitions(beanFactory)方法来装载。这个方法实际调用的是子类AbstractXmlApplicationContext中的loadBeanDefinitions方法,该方法通过创建一个BeanDefinition阅读器,通过阅读xml文件来加载和注册。给这个XmlBeanDefinitionReader对象赋上了一些初始值以后,再次通过调用重载的同名loadBeanDefinitions(XmlBeanDefinitionReader reader)方法。

	protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
		// 获取资源的定位
		// 这里getConfigResources是一个空实现,真正实现是调用子类的获取资源定位的方法
		// 比如:ClassPathXmlApplicationContext中进行了实现
		// 		而FileSystemXmlApplicationContext没有使用该方法
		Resource[] configResources = getConfigResources();
		if (configResources != null) {
			// XML Bean读取器调用其父类AbstractBeanDefinitionReader读取定位的资源
			reader.loadBeanDefinitions(configResources);
		}
		// 如果子类中获取的资源定位为空,则获取FileSystemXmlApplicationContext构造方法中setConfigLocations方法设置的资源
		String[] configLocations = getConfigLocations();
		if (configLocations != null) {
			// XML Bean读取器调用其父类AbstractBeanDefinitionReader读取定位的资源
			reader.loadBeanDefinitions(configLocations);
		}
	}

XmlBean读取器(XmlBeanDefinitionReader)调用其父类AbstractBeanDefinitionReader reader.loadBeanDefinitions方法读取Bean定义资源。

AbstractBeanDefinitionReader读取Bean定义资源,在其抽象父类AbstractBeanDefinitionReader中定 义了载入过程。

AbstractBeanDefinitionReader的loadBeanDefinitions方法源码如下:

	public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources)
			throws BeanDefinitionStoreException {
		// 获取在IoC容器初始化过程中设置的资源加载器
		ResourceLoader resourceLoader = getResourceLoader();
		if (resourceLoader == null) {
			throw new BeanDefinitionStoreException(
					"Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
		}

		if (resourceLoader instanceof ResourcePatternResolver) {
			// Resource pattern matching available.
			try {
				Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
				// 委派调用其子类XmlBeanDefinitionReader的方法,实现加载功能
				int loadCount = loadBeanDefinitions(resources);
				if (actualResources != null) {
					for (Resource resource : resources) {
						actualResources.add(resource);
					}
				}
				if (logger.isDebugEnabled()) {
					logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
				}
				return loadCount;
			} 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 loadCount = loadBeanDefinitions(resource);
			if (actualResources != null) {
				actualResources.add(resource);
			}
			if (logger.isDebugEnabled()) {
				logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
			}
			return loadCount;
		}
	}

通过传入参数location地址来获取资源resources,再将resources传入调用子类XmlBeanDefinitionReader的loadBeanDefinitions方法。

XmlBeanDefinitionReader的loadBeanDefinitions(EncodedResource encodedResource)方法如下:

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
	Assert.notNull(encodedResource, "EncodedResource must not be null");
	if (logger.isInfoEnabled()) {
		logger.info("Loading XML bean definitions from " + encodedResource.getResource());
	}
	Set<EncodedResource> 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的IO流
		InputStream inputStream = encodedResource.getResource().getInputStream();
		try {
			// 从InputStream中得到XML的解析源
			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通过特殊编码处理loadBeanDefinitions(new EncodedResource(resource)) (此处有使用到模板设计模式),通过doLoadBeanDefinitions方法来进行具体的读取过程。

	protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {
		try {
			// 通过DOM4J加载解析XML文件,最终形成Document对象
			Document doc = doLoadDocument(inputSource, resource);
			// 通过对Document对象的操作,完成BeanDefinition的加载和注册工作
            return registerBeanDefinitions(doc, resource);
		}
		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);
		}
	}

这里面首先通过DOM4J加载解析XML文件,最终形成Document对象,再通过对Document对象的操作,完成BeanDefinition的加载和注册工作。

	public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
		// 创建BeanDefinitionDocumentReader来解析Document对象,完成BeanDefinition解析
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		// 获得容器中已经注册的BeanDefinition数量
		int countBefore = getRegistry().getBeanDefinitionCount();
		//解析过程入口,BeanDefinitionDocumentReader只是个接口,具体的实现过程在DefaultBeanDefinitionDocumentReader完成
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		// 统计新的的BeanDefinition数量
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}

首先通过创建BeanDefinitionDocumentReader,再通过具体实现类DefaultBeanDefinitionDocumentReader的registerBeanDefinitions方法来进行真正的解析工作。

	@Override
	public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
		this.readerContext = readerContext;
		logger.debug("Loading bean definitions");
		// 获得Document的根元素<beans>标签
		Element root = doc.getDocumentElement();
		// 真正实现BeanDefinition解析和注册工作
		doRegisterBeanDefinitions(root);
	}

DefaultBeanDefinitionDocumentReader的doRegisterBeanDefinitions(Element root)方法源码如下:

	protected void doRegisterBeanDefinitions(Element root) {	
		// 这里使用了委托模式,将具体的BeanDefinition解析工作交给了BeanDefinitionParserDelegate去完成
		BeanDefinitionParserDelegate parent = this.delegate;
		this.delegate = createDelegate(getReaderContext(), root, parent);

		// 判断该根标签是否包含http://www.springframework.org/schema/beans默认命名空间
		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);
				if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
					if (logger.isInfoEnabled()) {
						logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
								"] not matching: " + getReaderContext().getResource());
					}
					return;
				}
			}
		}
		// 在解析Bean定义之前,进行自定义的解析,增强解析过程的可扩展性
		preProcessXml(root);
		// 委托给BeanDefinitionParserDelegate,从Document的根元素开始进行BeanDefinition的解析
		parseBeanDefinitions(root, this.delegate);
		// 在解析Bean定义之后,进行自定义的解析,增加解析过程的可扩展性
		postProcessXml(root);

		this.delegate = parent;
	}

 parseBeanDefinitions方法将Document从根元素开始解析

	protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
		// 加载的Document对象是否使用了Spring默认的XML命名空间(beans命名空间)
		if (delegate.isDefaultNamespace(root)) {
			// 获取Document对象根元素的所有子节点(bean标签、import标签、alias标签和其他自定义标签context、aop等)
			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;
					// bean标签、import标签、alias标签,则使用默认解析规则
					if (delegate.isDefaultNamespace(ele)) {
						parseDefaultElement(ele, delegate);
					}
					else {//像context标签、aop标签、tx标签,则使用用户自定义的解析规则解析元素节点
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
			// 如果不是默认的命名空间,则使用用户自定义的解析规则解析元素节点
			delegate.parseCustomElement(root);
		}
	}

通过委托判断是否是默认命名空间,如果是则使用parseDefaultElement方法解析默认元素(bean标签、import标签、alias标签和其他自定义标签context、aop等),如果不是默认命名空间,则通过parseCustomElement方法来解析用户自定义的元素节点(context标签、aop标签、tx标签)

parseDefaultElement源码如下:

	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)) {
			// recurse
			// 递归调用
			doRegisterBeanDefinitions(ele);
		}
	}

这里主要查看 processBeanDefinition如何解析bean标签:

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		// 解析<bean>标签,获取BeanDefinition
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
			// 如果需要,则装饰BeanDefinition对象
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// Register the final decorated instance.
				// 注册最终的BeanDefinition到BeanDefinitionRegistry(DefaultListableBeanFactory)
				BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
			}
			catch (BeanDefinitionStoreException ex) {
				getReaderContext().error("Failed to register bean definition with name '" +
						bdHolder.getBeanName() + "'", ele, ex);
			}
			// Send registration event.
			getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
		}
	}

这里先获取BeanDefinition,再通过BeanDefinitionReaderUtils.registerBeanDefinition方法来注册最终的BeanDefinition到BeanDefinitionRegistry(DefaultListableBeanFactory)。

解析bean标签,获取BeanDefinition的parseBeanDefinitionElement方法,是在BeanDefinitionParserDelegate中进行的:

	public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
		// 获取bean的id
		String id = ele.getAttribute(ID_ATTRIBUTE);
		// 获取bean的name
		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

		List<String> aliases = new ArrayList<>();
		if (StringUtils.hasLength(nameAttr)) {
			String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
			aliases.addAll(Arrays.asList(nameArr));
		}

		String beanName = id;
		if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
			beanName = aliases.remove(0);
			if (logger.isDebugEnabled()) {
				logger.debug("No XML 'id' specified - using '" + beanName +
						"' as bean name and " + aliases + " as aliases");
			}
		}

		if (containingBean == null) {
			// 检查bean的id或者name是否唯一
			checkNameUniqueness(beanName, aliases, ele);
		}
		// 解析<bean>标签,获取BeanDefinition对象
		AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
		if (beanDefinition != null) {
			if (!StringUtils.hasText(beanName)) {
				try {
					if (containingBean != null) {
						beanName = BeanDefinitionReaderUtils.generateBeanName(
								beanDefinition, this.readerContext.getRegistry(), true);
					}
					else {
						beanName = this.readerContext.generateBeanName(beanDefinition);
						// Register an alias for the plain bean class name, if still possible,
						// if the generator returned the class name plus a suffix.
						// This is expected for Spring 1.2/2.0 backwards compatibility.
						String beanClassName = beanDefinition.getBeanClassName();
						if (beanClassName != null &&
								beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
								!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
							aliases.add(beanClassName);
						}
					}
					if (logger.isDebugEnabled()) {
						logger.debug("Neither XML 'id' nor 'name' specified - " +
								"using generated bean name [" + beanName + "]");
					}
				}
				catch (Exception ex) {
					error(ex.getMessage(), ele);
					return null;
				}
			}
			String[] aliasesArray = StringUtils.toStringArray(aliases);
			// 将BeanDefinition对象和BeanName封装到BeanDefinitionHolder对象中
			return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
		}

		return null;
	}

注意:在解析元素过程中没有创建和实例化Bean对象,只是创建了Bean对象的定义类BeanDefinition,将元素中的 配置信息设置到BeanDefinition中作为记录,当依赖注入时才使用这些记录信息创建和实例化具体的Bean对象。

 

parseBeanDefinitionElement具体源码如下:

	public AbstractBeanDefinition parseBeanDefinitionElement(
			Element ele, String beanName, @Nullable BeanDefinition containingBean) {

		this.parseState.push(new BeanEntry(beanName));

		String className = null;
		// 获取bean标签的class属性
		if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
			className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
		}
		String parent = null;
		// 获取bean标签的parent属性
		if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
			parent = ele.getAttribute(PARENT_ATTRIBUTE);
		}

		try {
			// 创建BeanDefinition对象GenericBeanDefinition
			AbstractBeanDefinition bd = createBeanDefinition(className, parent);
			
			// 解析<bean>标签的属性
			parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
			/** 解析<bean>标签的子标签  --- begin**/
			// 解析<description>标签
			bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
			// 解析<meta>标签
			parseMetaElements(ele, bd);
			// 解析<lookup-method>标签
			parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
			// 解析<replaced-method>标签
			parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
			
			// 解析<constructor-arg>标签
			parseConstructorArgElements(ele, bd);
			// 解析<property>标签
			parsePropertyElements(ele, bd);
			// 解析<qualifier>标签
			parseQualifierElements(ele, bd);
			/** 解析<bean>标签的子标签  --- end**/

			bd.setResource(this.readerContext.getResource());
			bd.setSource(extractSource(ele));

			return bd;
		}
		catch (ClassNotFoundException ex) {
			error("Bean class [" + className + "] not found", ele, ex);
		}
		catch (NoClassDefFoundError err) {
			error("Class that bean class [" + className + "] depends on not found", ele, err);
		}
		catch (Throwable ex) {
			error("Unexpected failure during bean definition parsing", ele, ex);
		}
		finally {
			this.parseState.pop();
		}

		return null;
	}

上面方法中一些对一些配置如元信息(meta)、qualifier等的解析,我们在Spring中配置时使用的也不多,我们在 使用Spring的元素时,配置最多的是属性,因此我们下面继续分析源码,了解Bean的属性在解析时是如何设置的。

parsePropertyElements方法解析元素中的属性子元素,解析源码如下:

	/**
	 * property标签的解析
	 * Parse a property element.
	 */
	public void parsePropertyElement(Element ele, BeanDefinition bd) {
		String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
		if (!StringUtils.hasLength(propertyName)) {
			error("Tag 'property' must have a 'name' attribute", ele);
			return;
		}
		this.parseState.push(new PropertyEntry(propertyName));
		try {
			if (bd.getPropertyValues().contains(propertyName)) {
				error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
				return;
			}
			Object val = parsePropertyValue(ele, bd, propertyName);
			PropertyValue pv = new PropertyValue(propertyName, val);
			parseMetaElements(ele, pv);
			pv.setSource(extractSource(ele));
			bd.getPropertyValues().addPropertyValue(pv);
		}
		finally {
			this.parseState.pop();
		}
	}






	public Object parsePropertyValue(Element ele, BeanDefinition bd, @Nullable String propertyName) {
		String elementName = (propertyName != null) ?
						"<property> element for property '" + propertyName + "'" :
						"<constructor-arg> element";

		// Should only have one child element: ref, value, list, etc.
		NodeList nl = ele.getChildNodes();
		Element subElement = null;
		for (int i = 0; i < nl.getLength(); i++) {
			Node node = nl.item(i);
			if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&
					!nodeNameEquals(node, META_ELEMENT)) {
				// Child element is what we're looking for.
				if (subElement != null) {
					error(elementName + " must not contain more than one sub-element", ele);
				}
				else {
					subElement = (Element) node;
				}
			}
		}

		boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
		boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
		if ((hasRefAttribute && hasValueAttribute) ||
				((hasRefAttribute || hasValueAttribute) && subElement != null)) {
			error(elementName +
					" is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
		}

		if (hasRefAttribute) {
			String refName = ele.getAttribute(REF_ATTRIBUTE);
			if (!StringUtils.hasText(refName)) {
				error(elementName + " contains empty 'ref' attribute", ele);
			}
			// 引用类型属性值信息
			RuntimeBeanReference ref = new RuntimeBeanReference(refName);
			ref.setSource(extractSource(ele));
			return ref;
		}
		else if (hasValueAttribute) {
			// 简单类型属性值信息
			TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
			valueHolder.setSource(extractSource(ele));
			return valueHolder;
		}
		else if (subElement != null) {
			return parsePropertySubElement(subElement, bd);
		}
		else {
			// Neither child element nor "ref" or "value" attribute found.
			error(elementName + " must specify a ref or value", ele);
			return null;
		}
	}

通过对上述源码的分析,我们可以了解在Spring配置文件中,元素中元素的相关配置是如何处理的:

a.ref被封装为指向依赖对象一个引用。

b.value配置都会封装成一个字符串类型的对象。

c.ref和value都通过“解析的数据类型属性值.setSource(extractSource(ele));”方法将属性值/引用与所引用 的属性关联起来。

 

经过对SpringBean定义资源文件转换的Document对象中的元素层层解析,SpringIOC现在已经将XML形式定义的 Bean定义资源文件转换为SpringIOC所识别的数据结构——BeanDefinition,它是Bean定义资源文件中配置的 POJO对象在SpringIOC容器中的映射,我们可以通过AbstractBeanDefinition为入口,看到了IOC容器进行索引、 查询和操作。 通过SpringIOC容器对Bean定义资源的解析后,IOC容器大致完成了管理Bean对象的准备工作,即初始化过程,但是 最为重要的依赖注入还没有发生,现在在IOC容器中BeanDefinition存储的只是一些静态信息,接下来需要向容器 注册Bean定义信息才能全部完成IOC容器的初始化过程。

 

让我们继续跟踪程序的执行顺序,接下来我们来分析DefaultBeanDefinitionDocumentReader对Bean定义转换的 Document对象解析的流程中,在其parseDefaultElement方法中完成对Document对象的解析后得到封装 BeanDefinition的BeanDefinitionHold对象,然后调用BeanDefinitionReaderUtils的 registerBeanDefinition方法向IOC容器注册解析的Bean,BeanDefinitionReaderUtils的注册的源码如下:

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

		// Register bean definition under primary name.
		String beanName = definitionHolder.getBeanName();
		// 以name为key,以BeanDefinition为Value,注册到Registry
		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);
			}
		}
	}

当调用BeanDefinitionReaderUtils向IOC容器注册解析的BeanDefinition时,真正完成注册功能的是 DefaultListableBeanFactory。

 

DefaultListableBeanFactory向IOC容器注册解析后的BeanDefinition:DefaultListableBeanFactory 中使用一个HashMap的集合对象存放IOC容器中注册解析的BeanDefinition,向IOC容器注册的主要源码如下:

	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 oldBeanDefinition;

		oldBeanDefinition = this.beanDefinitionMap.get(beanName);
		if (oldBeanDefinition != null) {
			if (!isAllowBeanDefinitionOverriding()) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
						"': There is already [" + oldBeanDefinition + "] bound.");
			}
			else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
				// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
				if (this.logger.isWarnEnabled()) {
					this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
							"' with a framework-generated bean definition: replacing [" +
							oldBeanDefinition + "] with [" + beanDefinition + "]");
				}
			}
			else if (!beanDefinition.equals(oldBeanDefinition)) {
				if (this.logger.isInfoEnabled()) {
					this.logger.info("Overriding bean definition for bean '" + beanName +
							"' with a different definition: replacing [" + oldBeanDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			else {
				if (this.logger.isDebugEnabled()) {
					this.logger.debug("Overriding bean definition for bean '" + beanName +
							"' with an equivalent definition: replacing [" + oldBeanDefinition +
							"] 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;
					if (this.manualSingletonNames.contains(beanName)) {
						Set<String> 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;
		}

		// 检查是否有同名的BeanDefinition 已经在IOC容器中注册
		if (oldBeanDefinition != null || containsSingleton(beanName)) {
			// 重置已经注册过的BeanDefinition缓存
			resetBeanDefinition(beanName);
		}
	}

至此,Bean定义资源文件中配置的Bean被解析过后,已经注册到IOC容器中,被容器管理起来,真正完成了IOC容器 初始化所做的全部工作。现在IOC容器中已经建立了整个Bean的配置信息,这些BeanDefinition信息已经可以使 用,并且可以被检索,IOC容器的作用就是对这些注册的Bean定义信息进行处理和维护。这些的注册的Bean定义信息 是IOC容器控制反转的基础,正是有了这些注册的数据,容器才可以进行依赖注入。

 

总结: 现在通过上面的代码,总结一下IOC容器初始化的基本步骤:

(1).初始化的入口在容器实现中的refresh()调用来完成。

(2).对bean定义载入IOC容器使用的方法是loadBeanDefinition,其中的大致过程如下:

通过ResourceLoader来完成资源文件位置的定位,DefaultResourceLoader是默认的实现,同时上下文本身就给 出了ResourceLoader的实现,可以从类路径,文件系统,URL等方式来定为资源位置。如果是XmlBeanFactory作为 IOC容器,那么需要为它指定bean定义的资源,也就是说bean定义文件时通过抽象成Resource来被IOC容器处理的, 容器通过BeanDefinitionReader来完成定义信息的解析和Bean信息的注册,往往使用的是 XmlBeanDefinitionReader来解析bean的xml定义文件-实际的处理过程是委托给 BeanDefinitionParserDelegate来完成的,从而得到bean的定义信息,这些信息在Spring中使用 BeanDefinition对象来表示-这个名字可以让我们想到loadBeanDefinition,RegisterBeanDefinition这些相关 方法-他们都是为处理BeanDefinitin服务的,容器解析得到BeanDefinition以后,需要把它在IOC容器中注册,这 由IOC实现BeanDefinitionRegistry接口来实现。注册过程就是在IOC容器内部维护的一个HashMap来保存得到的 BeanDefinition的过程。这个HashMap是IOC容器持有Bean信息的场所,以后对Bean的操作都是围绕这个HashMap 来实现的。

然后我们就可以通过BeanFactory和ApplicationContext来享受到SpringIOC的服务了,在使用IOC容器的时候,我 们注意到除了少量粘合代码,绝大多数以正确IOC风格编写的应用程序代码完全不用关心如何到达工厂,因为容器将 把这些对象与容器管理的其他对象钩在一起。基本的策略是把工厂放到已知的地方,最好是放在对预期使用的上下文 有意义的地方,以及代码将实际需要访问工厂的地方。Spring本身提供了对声明式载入web应用程序用法的应用程序 上下文,并将其存储在ServletContext中的框架实现。 

 

在使用SpringIOC容器的时候我们还需要区别两个概念: BeanFactory和FactoryBean,其中BeanFactory指的是IOC容器的编程抽象,比如ApplicationContext, XmlBeanFactory等,这些都是IOC容器的具体表现,需要使用什么样的容器由客户决定,但Spring为我们提供了丰 富的选择。FactoryBean只是一个可以在IOC而容器中被管理的一个Bean,是对各种处理过程和资源使用的抽 象,FactoryBean在需要时产生另一个对象,而不返回FactoryBean本身,我们可以把它看成是一个抽象工厂,对它 的调用返回的是工厂生产的产品。所有的FactoryBean都实现特殊的 org.springframework.beans.factory.FactoryBean接口,当使用容器中FactoryBean的时候,该容器不会返回 FactoryBean本身,而是返回其生成的对象。Spring包括了大部分的通用资源和服务访问抽象的FactoryBean的实 现,其中包括:对JNDI查询的处理,对代理对象的处理,对事务性代理的处理,对RMI代理的处理等,这些我们都可 以看成是具体的工厂,看成是Spring为我们建立好的工厂。也就是说Spring通过使用抽象工厂模式为我们准备了一系 列工厂来生产一些特定的对象,免除我们手工重复的工作,我们要使用时只需要在IOC容器里配置好就能很方便的使 用了。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值