Spring源码深度解析(XmlBeanFactory源码解析上)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_26323323/article/details/80968920

前言:

    Spring容器有多种实现方式,一般来说可分为:BeanFactory和ApplicationContext

    * BeanFactory提供了容器的基本功能,如getBean()等功能

    * ApplicationContext接口继承了BeanFactory,不但实现了BeanFactory的所有功能,还对其进行了扩展。

    扩展功能如下:1)MessageSource,提供国际化的消息访问;2)资源访问,如URL和文件;3)事件传播特性,即支持AOP特性;4)载入多个有继承关系的上下文,使得每一个上下文都专注与一个特定的层次,比如应用的Web层

    本文则基于BeanFactory接口的实现类XMLBeanFactory来介绍其加载xml文件的过程

    笔者使用SpringBoot来进行开发,spring-boot-start-parent版本为1.5.3.RELEASE,所依赖的Spring组件(如context、core)等版本为4.3.8.RELEASE

1.XMLBeanFactory的基本使用

    1)创建实体类Student

@Data
public class Student {

	private int id;
	private String name;
}

    2)创建文件beans.xml,具体内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="student" class="test.Student"/>
</beans>

    3)测试方法

public class Test {
	public static void main(String[] args) {
		XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("beans.xml"));
		Student bean = (Student) bf.getBean("student");
		System.out.println(bean); //结果为:Student(id=0, name=null)
    }
}

   以上便是通过加载xml的方式来获取bean

2.写在分析XmlBeanFactory源码之前

    在查看XmlBeanFactory实现其相关功能的源码以前,我们可以大胆猜想一下,如果是我们自己,那应该如何来实现这个功能?

    如果是我的话,最简单的思路就是:

    1)先使用一个解析工具(一般来说就是DOM解析或者SAX解析)来解析beans.xml,获取其内容(一般解析完成之后都是获取一个Document)

    2)解析该Document,组装bean的基本信息,如name、class等信息,将这些信息放到一个bean的实体之中

    3)将组装完的bean信息,放到一个map中,name作为key,class对应的实例作为value,这样用户就可以通过getBean等方法来获取该bean

    大胆设想这种实现BeanFactory的方式,总体看来这样实现简单易用也是不错的,读者也可以自己设想下其实现方式。

3.XmlBeanFactory源码架构分析

    下面跟随笔者先大概看一下XmlBeanFactory加载bean.xml的大概架构

    1)new XmlBeanFactory(Resource resource)构造XmlBeanFactory

	private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);// 自定义的Reader

	public XmlBeanFactory(Resource resource) throws BeansException {// 默认构造方式
		this(resource, null);// 调用下一个构造方法,parentBeanFactory默认为null
	}

	public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
		super(parentBeanFactory);
		this.reader.loadBeanDefinitions(resource); // 主要功能实现
	}

    2)reader.loadBeanDefinitions(Resource resource) 解析器加载resource

	public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
        ...
		try {
            // 1.从resource中获取流信息
			InputStream inputStream = encodedResource.getResource().getInputStream();
			try {
				InputSource inputSource = new InputSource(inputStream);
				if (encodedResource.getEncoding() != null) {
					inputSource.setEncoding(encodedResource.getEncoding());
				}
                // 2.加载流信息
				return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
			}
			finally {
				inputStream.close();
			}
		}
        ...
	}

    3)doLoadBeanDefinitions(...)加载流信息

	protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {
		try {
            // 1.通过xml解析inputStream来获取xml对应的Document
			Document doc = doLoadDocument(inputSource, resource);
            // 2.解析Document,注册其中的bean
			return registerBeanDefinitions(doc, resource);
		}
        ...
	}

    总结:通过以上对XmlBeanFactory结构的分析,可知,其主要功能也是按照我们的猜想来进行的

    主要分为三个步骤:

        * 将beans.xml加载为流信息

        * 解析该流信息,将其解析为一个Document

        * 加载该Document,注册其中的bean(到某一个地方),该步骤也是最重要的步骤

    下面按照这三个步骤,逐步解析XmlBeanFactory功能

4.将beans.xml加载为流信息

    由XMLBeanFactory的构造方法可知,构造器的入参为Resource,下面看一个Resource的主要方法:

/**
    主要方法:
 * @see #getInputStream()
 * @see #getURL()
 * @see #getURI()
 * @see #getFile()
 
     主要实现:
 * @see WritableResource
 * @see ContextResource
 * @see UrlResource
 * @see ClassPathResource
 * @see FileSystemResource
 * @see PathResource
 * @see ByteArrayResource
 * @see InputStreamResource
 */
public interface Resource extends InputStreamSource {}

   主要实现方式有以上几种,通常我们使用的就是ClassPathResource(将配置文件放到src/main/resources中),或者FileSystemResource(将配置文件放到系统盘某个路径下)

    在XmlBeanDefinitionReader.loadBeanDefinitions(EncodedResource encodedResource)中可知

InputStream inputStream = encodedResource.getResource().getInputStream();

    InputStream的获取是通过Resource.getInputStream()方法来实现的,下面来查看一下ClassPathResource.getInputStream()方法:

	@Override
	public InputStream getInputStream() throws IOException {
		InputStream is;
        // 默认情况下clazz为null
		if (this.clazz != null) {
			is = this.clazz.getResourceAsStream(this.path);
		}
        // classLoader不为空,默认为ClassUtils.getDefaultClassLoader(),也就是Thread.currentThread().getContextClassLoader()
		else if (this.classLoader != null) {
            // 所以通过classLoader来加载path资源
			is = this.classLoader.getResourceAsStream(this.path);
		}
		else {
			is = ClassLoader.getSystemResourceAsStream(this.path);
		}
		if (is == null) {
			throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist");
		}
		return is;
	}

    总结:由上可知,bean.xml转换为流信息,主要是通过classLoader.getResourceAsStream()方法来实现的

5.解析InputStream,将其解析为一个Document

    解析流为Document的主要代码为XmlBeanDefinitionReader.doLoadBeanDefinitions(InputSource inputSource, Resource resource)方法

	protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {
		try {
            // 1.通过xml解析inputStream来获取xml对应的Document
			Document doc = doLoadDocument(inputSource, resource);
            ...
		}
        ...
	}

    下面来解析这个doLoadDocument方法

    1)doLoadDocument()

	protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
		return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
				getValidationModeForResource(resource), isNamespaceAware());
	}

    2)loadDocument()

	public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
			ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {

		DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
		if (logger.isDebugEnabled()) {
			logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
		}
        // 1.创建DocumentBuilder,直接从DocumentBuilderFactory中获取,通过factory.newDocumentBuilder()方法
		DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
        // 2.使用DocumentBuilder来解析流信息
		return builder.parse(inputSource);
	}

    3)build.parse()

    public Document parse(InputSource is) throws SAXException, IOException {
        if (is == null) {
            throw new IllegalArgumentException(
                DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN,
                "jaxp-null-input-source", null));
        }
        if (fSchemaValidator != null) {
            if (fSchemaValidationManager != null) {
                fSchemaValidationManager.reset();
                fUnparsedEntityHandler.reset();
            }
            resetSchemaValidator();
        }
        // 通过DOM解析,来获取Document
        domParser.parse(is);
        Document doc = domParser.getDocument();
        domParser.dropDocumentReferences();
        return doc;
    }

    总结:由上文可知,Spring使用了DOM解析的方式来解析InputStream,最终获取Document

6.加载该Document,注册其中的bean(到某一个地方)

    下面来看XmlBeanDefinitionReader.doLoadBeanDefinitions(InputSource inputSource, Resource resource)方法的下半段

	protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {
		try {
            ...
            // 2.解析Document,注册其中的bean
			return registerBeanDefinitions(doc, resource);
		}
        ...
	}

    1)XmlBeanDefinitionReader.registerBeanDefinitions()

	public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        // 1.创建BeanDefinitionDocumentReader,BeanDefinitionDocumentReader接口默认实现为DefaultBeanDefinitionDocumentReader
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		int countBefore = getRegistry().getBeanDefinitionCount();
        // 2.注册Document中的元素
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}

    2)DefaultBeanDefinitionDocumentReader.registerBeanDefinitions()

	public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
		this.readerContext = readerContext;
		logger.debug("Loading bean definitions");
        // 1.获取rootElement
		Element root = doc.getDocumentElement();
        // 2.注册
		doRegisterBeanDefinitions(root);
	}

    // doRegisterBeanDefinitions()
	protected void doRegisterBeanDefinitions(Element root) {
		
        // 前置处理(暂时为空,用户可自定义实现)
		preProcessXml(root);
        // 真正的解析处理
		parseBeanDefinitions(root, this.delegate);
        // 后置处理(暂时为空,用户可自定义实现)
		postProcessXml(root);

		this.delegate = parent;
	}

    // parseBeanDefinitions()
	protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
		if (delegate.isDefaultNamespace(root)) {
            // 1.获取所有的子节点
			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)) {
                        // 2.使用默认实现(本例中没有自定义标签,所以会使用该默认实现)
						parseDefaultElement(ele, delegate);
					}
					else {
                        // 用户自定义实现
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
			delegate.parseCustomElement(root);
		}
	}

    // parseDefaultElement()
    // 根据不同的nodeName,对应不同的解析方案,暂时只分析最重要的一个BEAN_ELEMENT的解析
	private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
		if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
			importBeanDefinitionResource(ele);
		}
		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
			processAliasRegistration(ele);
		}
        // 本例中最重要的解析
		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
			processBeanDefinition(ele, delegate);
		}
		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
			// recurse
			doRegisterBeanDefinitions(ele);
		}
	}

    3)DefaultBeanDefinitionDocumentReader.processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)最重要的方法

	protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        // 1.BeanDefinitionHolder用于全方位的来描述一个bean信息,包括name/class/alias/等一系列属性,将element解析为BeanDefinitionHolder
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
            // 2.对其属性进行装饰
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// 3.将bean实例注册到(某一个地方)
				BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
			}
			catch (BeanDefinitionStoreException ex) {
				getReaderContext().error("Failed to register bean definition with name '" +
						bdHolder.getBeanName() + "'", ele, ex);
			}
			// 4.发送注册完成事件给相应的监听器
			getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
		}
	}

    4)BeanDefinitionParserDelegate.parseBeanDefinitionElement()

    将Document中的Element解析为一个BeanDefinitionHolder,BeanDefinitionHolder为一个bean信息的综合描述

	public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
		return parseBeanDefinitionElement(ele, null);
	}

    // parseBeanDefinitionElement()
	public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
        // 1.获取id 和 name属性值
		String id = ele.getAttribute(ID_ATTRIBUTE);
		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

		List<String> aliases = new ArrayList<String>();
		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");
			}
		}
        // 2.判断beanName是否重复,如果已有该beanName,则报错
		if (containingBean == null) {
			checkNameUniqueness(beanName, aliases, ele);
		}
        // 3.解析Element元素(重要方法)
		AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
		if (beanDefinition != null) {
            // 4.如果用户没有写id,则自动生成一个beanName
			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);
						}
					}
					...
			}
			String[] aliasesArray = StringUtils.toStringArray(aliases);
            
            // 5.组装为BeanDefinitionHolder
			return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
		}

		return null;
	}
        
        
    // parseBeanDefinitionElement()
    	public AbstractBeanDefinition parseBeanDefinitionElement(
			Element ele, String beanName, BeanDefinition containingBean) {

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

        // 1.获取class属性值
		String className = null;
		if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
			className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
		}

		try {
			String parent = null;
			if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
				parent = ele.getAttribute(PARENT_ATTRIBUTE);
			}
            // 2.创建AbstractBeanDefinition,AbstractBeanDefinition为bean的描述信息类(重要方法)
			AbstractBeanDefinition bd = createBeanDefinition(className, parent);

            // 3.下面的parse方法均为对AbstractBeanDefinition中属性的补充
			parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
			bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

			parseMetaElements(ele, bd);
			parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
			parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

			parseConstructorArgElements(ele, bd);
			parsePropertyElements(ele, bd);
			parseQualifierElements(ele, bd);

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

			return bd;
		}
		...

		return null;
	}
        
    // createBeanDefinition()
    	protected AbstractBeanDefinition createBeanDefinition(String className, String parentName)
			throws ClassNotFoundException {

		return BeanDefinitionReaderUtils.createBeanDefinition(
				parentName, className, this.readerContext.getBeanClassLoader());
	}
        
    // createBeanDefinition()   
    	public static AbstractBeanDefinition createBeanDefinition(
			String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException {

		GenericBeanDefinition bd = new GenericBeanDefinition();
		bd.setParentName(parentName);
		if (className != null) {
			if (classLoader != null) {
                // 由className反射获取BeanClass
				bd.setBeanClass(ClassUtils.forName(className, classLoader));
			}
			else {
				bd.setBeanClassName(className);
			}
		}
		return bd;
	}

    总结:整个4)方法,总体来说就是为了获取对bean的完整描述信息,描述信息都存放在BeanDefinitionHolder类中;BeanClass信息由反射的方式来获取

    5)将BeanDefinitionHolder实例注册到(某一个地方)

        4)方法已经将Element元素解析为一个完整的BeanDefinitionHolder类,里面包含了Element元素所有的基本信息,下面就看下,如何注册

	protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// 主要就是这段代码
				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));
		}
	}

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

		// 1.获取beanName
		String beanName = definitionHolder.getBeanName();
        // 2.进行注册
		registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

		...
	}

    // DefaultListableBeanFactory.registerBeanDefinition(),默认实现为DefaultListableBeanFactory
	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {

		...
		BeanDefinition oldBeanDefinition;
        // 1.从当前的map中获取,是否已有该bean,如果已有该bean,则重新覆盖
        // map为:private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256);
		oldBeanDefinition = this.beanDefinitionMap.get(beanName);
		if (oldBeanDefinition != null) {
			...
			this.beanDefinitionMap.put(beanName, beanDefinition);
		}
        // 2.当前bean第一次加载
		else {
			if (hasBeanCreationStarted()) {
				// Cannot modify startup-time collection elements anymore (for stable iteration)
				synchronized (this.beanDefinitionMap) {
                    // 3.同步的情况下,将该bean放入map中
					this.beanDefinitionMap.put(beanName, beanDefinition);
					List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
					updatedDefinitions.addAll(this.beanDefinitionNames);
					updatedDefinitions.add(beanName);
					this.beanDefinitionNames = updatedDefinitions;
					if (this.manualSingletonNames.contains(beanName)) {
						Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
						updatedSingletons.remove(beanName);
						this.manualSingletonNames = updatedSingletons;
					}
				}
			}
			...
	}

    总结5):由以上分析可知,注册行为就是将 beanName和beanDefinition 放入到DefaultListableBeanFactory的beanDefinitionMap中去

    总结:

    1)由6整个步骤可知:在获取Document之后,注册器所做的就是依次解析所有的Element,将Element解析为一个BeanDefinitionHolder,最后将beanName和对应的BeanDefinitionHolder放入到一个ConcurrentHashMap中去

    2)到此为止,XMLBeanFactory的构造方法解析完毕,总结下其过程为:

        * 将beans.xml文件读到内存,包装为InputStream

        * DOM解析的方式来解析InputStream,最后生成一个Document

        * 注册器解析Document,解析出Document的每一个Element

        * 将Element解析为一个BeanDefinitionHolder

        * 最后将beanName对应的BeanDefinitionHolder放入ConcurrentHashMap中,完成注册步骤

参考:Spring源码深度解析(郝佳)

















 

猜你喜欢

转载自blog.csdn.net/qq_26323323/article/details/80968920