编程知识 cdmana.com

Spring5

XML

通过读取xml注册bean

<?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="user" class="com.jame.pojo.User"/>
</beans>
public static void test1(){
		XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("beans.xml"));
		Object o = factory.getBean("user");
		System.out.println(o);
	}

首先看XmlBeanFactory结构

diagram

XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("beans.xml"));

在创建XmlBeanFactory时传入了一个ClassPathResource对象,先来看这个对象

ClassPathResource

​ 在java中将不同的资源抽象成URL,通过注册不同的handler(URLStreamHandler)来处理不同的资源的读取逻辑,而URL没有提供一些基本的方法,这些都是Spring对内部使用到的资源实现了自己的抽象结构:Resource接口来封装底层资源

​ InputStreamSource封装任何能返回InputStream的类,比如File,ClassPath下的资源等等,它只有定义一个方法:getInputStream(); 该方法返回一个新的InputStream对象

​ Resource接口抽象了所有的Spring内部使用到的底层资源,首先它定义了3个判断当前资源状态的方法,存在性(exists),可读性(isReadable),是否处于打开状态(isOpen),另外Resource接口还提供不同资源到URL URI File类型的转换,以及获取lastModified属性,文件名(不带路径信息的文件名,getFilename())的方法,创建基于当前路径创建相对资源的方法 createRelative()

有了Resource接口后便可以对资源文件进行统一处理

ClassPathResource

public ClassPathResource(String path, @Nullable ClassLoader classLoader) {
    Assert.notNull(path, "Path must not be null");
    String pathToUse = StringUtils.cleanPath(path);
    if (pathToUse.startsWith("/")) {
        pathToUse = pathToUse.substring(1);
    }
    this.path = pathToUse;
    this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
}

当通过Resource相关类完成了对配置文件进行封装后,配置文件的读取工作就交给XmlBeanDefinitionReader来处理

接下来就开始进入构造方法

XmlBeanFactory

public XmlBeanFactory(Resource resource) throws BeansException {
    //调用XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory)构造方法
    this(resource, null);
}
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
    super(parentBeanFactory);
    //加载资源的切入点
    this.reader.loadBeanDefinitions(resource);
}

在进行解析xml文件之前,先看一下super调用的方法

AbstractAutowireCapableBeanFactory

public AbstractAutowireCapableBeanFactory() {
    super();
    //忽略给定接口的自动装配功能
    //默认情况下获取A,而A的Bean属性还有B,而B还没有初始化,那么Spring会将B初始化,
    //但是某些情况下不会初始化B,例如B继承了BeanFactoryAware接口
    ignoreDependencyInterface(BeanNameAware.class);
    ignoreDependencyInterface(BeanFactoryAware.class);
    ignoreDependencyInterface(BeanClassLoaderAware.class);
}

现在可以看this.reader.loadBeanDefinitions(resource);方法了

主要流程如下

  1. 封装资源文件 进入XmlBeanDefinitionReader后先对参数Resource使用EncodedResource类进行封装
  2. 获取输入流,从Resource中获取对应的InputStream并构造InputSource
  3. 通过构造的InputSource实例和Resource实例继续调用函数doLoadBeanDefinitions

XmlBeanDefinitionReader

@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
    return loadBeanDefinitions(new EncodedResource(resource));
}

EncodedResource的作用是对资源文件的编码进行处理,主要逻辑体现在getReader()方法中,当设置了编码Spring就会使用相应的编码作为输入的编码

EncodedResource

public Reader getReader() throws IOException {
    if (this.charset != null) {
        return new InputStreamReader(this.resource.getInputStream(), this.charset);
    }
    else if (this.encoding != null) {
        return new InputStreamReader(this.resource.getInputStream(), this.encoding);
    }
    else {
        return new InputStreamReader(this.resource.getInputStream());
    }
}

当构造好encodedResource对象后,再次传入了loadBeanDefinitions(new EncodedResource(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 == 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 {
        //从encodedResource中获取Resource对象,然后再从Resource中获取InputStream对象
        InputStream inputStream = encodedResource.getResource().getInputStream();
        try {
            //这个类并不来自Spring,全路径为org.xml.sax
            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();
        }
    }
}
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
    throws BeanDefinitionStoreException {

    try {
        //通过inputSource获取Document对象
        Document doc = doLoadDocument(inputSource, resource);
        int count = registerBeanDefinitions(doc, resource);
        if (logger.isDebugEnabled()) {
            logger.debug("Loaded " + count + " bean definitions from " + resource);
        }
        return count;
    }
    //剩下全部都是异常处理

上面的代码其实就做了3件事

  1. 获取对XML文件的验证模式
  2. 加载XML,并得到对应的Document
  3. 根据返回的Document注册Bean信息

首先来看第一件事:获取xml文件验证模式

简单说下DTD和XSD区别

DTD是一种xml约束模式语言,一个DTD文档包含:元素的定义规则,元素间关系的定义规则,元素可使用规则,可使用的实体或符号规则

要是用DTD验证模式只需要在XML文件头部声明即可

XML Schema 语言就是XSD 它描述了xml文档的结构,可以指定一个xml schema来验证某个xml,xml schema本身就是一个xml文档,可以用通用xml解析器解析它

在使用xml schema文档对xml实例文档进行检验,除了要声明名称空间外,还必须指定该名称空间所对应的xml schema文档储存位置,通过schemaLocation属性来指定xml schema文件位置或URL地址

验证模式的读取

XmlBeanDefinitionReader

protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
    return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
                                            getValidationModeForResource(resource), isNamespaceAware());
}
protected int getValidationModeForResource(Resource resource) {
    int validationModeToUse = getValidationMode();
    //如果手动指定验证模式则使用指定的验证模式
    if (validationModeToUse != VALIDATION_AUTO) {
        return validationModeToUse;
    }
    int detectedMode = detectValidationMode(resource);
    //如果未指定则使用自动检测
    if (detectedMode != VALIDATION_AUTO) {
        return detectedMode;
    }
    return VALIDATION_XSD;
}

detectValidationMode(resource);自动检测验证的模式

protected int detectValidationMode(Resource resource) {
    if (resource.isOpen()) {
        throw new BeanDefinitionStoreException(
            "Passed-in Resource [" + resource + "] contains an open stream: " +
            "cannot determine validation mode automatically. Either pass in a Resource " +
            "that is able to create fresh streams, or explicitly specify the validationMode " +
            "on your XmlBeanDefinitionReader instance.");
    }

    InputStream inputStream;
    try {
        inputStream = resource.getInputStream();
    }
    catch (IOException ex) {
        throw new BeanDefinitionStoreException(
            "Unable to determine validation mode for [" + resource + "]: cannot open InputStream. " +
            "Did you attempt to load directly from a SAX InputSource without specifying the " +
            "validationMode on your XmlBeanDefinitionReader instance?", ex);
    }

    try {
        //又交给detectValidationMode去完成验证
        return this.validationModeDetector.detectValidationMode(inputStream);
    }
    catch (IOException ex) {
        throw new BeanDefinitionStoreException("Unable to determine validation mode for [" +
                                               resource + "]: an error occurred whilst reading from the InputStream.", ex);
    }
}

XmlValidationModeDetector

//判断方法就是是否包含DOCTYPE,如果包含就是DTD,否则就是XSD
public int detectValidationMode(InputStream inputStream) throws IOException {
    // Peek into the file to look for DOCTYPE.
    BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
    try {
        boolean isDtdValidated = false;
        String content;
        while ((content = reader.readLine()) != null) {
            content = consumeCommentTokens(content);
            //如果读取的是空行或者是注释略过
            if (this.inComment || !StringUtils.hasText(content)) {
                continue;
            }
            if (hasDoctype(content)) {
                isDtdValidated = true;
                break;
            }
            //如果读到<开始符号,验证模式一定会在开始符号之前
            if (hasOpeningTag(content)) {
                // End of meaningful data...
                break;
            }
        }
        return (isDtdValidated ? VALIDATION_DTD : VALIDATION_XSD);
    }
    catch (CharConversionException ex) {
        // Choked on some character encoding...
        // Leave the decision up to the caller.
        return VALIDATION_AUTO;
    }
    finally {
        reader.close();
    }
}

获取Document

通过验证就可以进行Document加载了,同样在XmlBeanFactoryReader类中没有实现,而是调用了loadDocument方法来实现

DocumentLoader I

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

这是个接口,他的实现类为

DefaultDocumentLoader

//通过SAX解析XML文档
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
                             ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
	//创建DocumentBuilderFactory对象
    DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
    if (logger.isTraceEnabled()) {
        logger.trace("Using JAXP provider [" + factory.getClass().getName() + "]");
    }
    //创建DocumentBuilder对象
    DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
    //解析inputSource来获取Document对象
    return builder.parse(inputSource);
}

主要来看一下doLoadDocument方法传入的 getEntityResolver()参数

XmlBeanDefinitionReader

protected EntityResolver getEntityResolver() {
    if (this.entityResolver == null) {
        // Determine default EntityResolver to use.
        ResourceLoader resourceLoader = getResourceLoader();
        if (resourceLoader != null) {
            this.entityResolver = new ResourceEntityResolver(resourceLoader);
        }
        else {
            this.entityResolver = new DelegatingEntityResolver(getBeanClassLoader());
        }
    }
    return this.entityResolver;
}

EntityResoulver用法

如果SAX应用程序需要实现自定义处理外部实体,必须要实现此接口并使用setEntutyResolver方法向SAX驱动器注册一个实例,--对于解析一个XML,SAX首先读取该XML文档上的声明,根据声明去寻找对于的DTD定义,以便对文档进行验证,默认是从网络上下载对应的DTD声明,而EntityResolver的作用就是项目本身就可以提供一个DTD文件声明的方法,由程序来寻找DTD声明的过程,比如讲DTD文件放到项目的某处,在实现时直接将此文档读取返回给SAX即可,不用通过网络来寻找相应的声明

EntityResolver的接口方法声明

EntityResolver I

public abstract InputSource resolveEntity (String publicId,String systemId)

如果解析验证模式为XSD的配置文件会读取到两个参数

publicId : null

systemId : xxxxxxxxxxx

而解析验证模式为DTD的配置文件

publicId : xxx

systemId : xxx

根据之前Spring通过getEntityResilver()方法对EntityResolver的获取,Spring中使用DelegatingEntityResolver类为EntityResolver的实现类,resolverEntity的实现方法如下

DelegatingEntityResolver

public InputSource resolveEntity(@Nullable String publicId, @Nullable String systemId)
    throws SAXException, IOException {

    if (systemId != null) {
        if (systemId.endsWith(DTD_SUFFIX)) {
            //如果是dtd从这里解析
            return this.dtdResolver.resolveEntity(publicId, systemId);
        }
        else if (systemId.endsWith(XSD_SUFFIX)) {
            //通过META-INF/Spring.schemas解析
            return this.schemaResolver.resolveEntity(publicId, systemId);
        }
    }

    // Fall back to the parser's default behavior.
    return null;
}

直接截取后缀来判断是那种解析类型

如果是DTD,会去当前路径下寻找,如果是XSD,默认是到META-INF/Spring.schemas文件中找到对应systemid的XSD文件并加载

BeansDtdResolver

public InputSource resolveEntity(@Nullable String publicId, @Nullable String systemId) throws IOException {
    if (logger.isTraceEnabled()) {
        logger.trace("Trying to resolve XML entity with public ID [" + publicId +
                     "] and system ID [" + systemId + "]");
    }

    if (systemId != null && systemId.endsWith(DTD_EXTENSION)) {
        int lastPathSeparator = systemId.lastIndexOf('/');
        int dtdNameStart = systemId.indexOf(DTD_NAME, lastPathSeparator);
        if (dtdNameStart != -1) {
            String dtdFile = DTD_NAME + DTD_EXTENSION;
            if (logger.isTraceEnabled()) {
                logger.trace("Trying to locate [" + dtdFile + "] in Spring jar on classpath");
            }
            try {
                Resource resource = new ClassPathResource(dtdFile, getClass());
                InputSource source = new InputSource(resource.getInputStream());
                source.setPublicId(publicId);
                source.setSystemId(systemId);
                if (logger.isTraceEnabled()) {
                    logger.trace("Found beans DTD [" + systemId + "] in classpath: " + dtdFile);
                }
                return source;
            }
            catch (FileNotFoundException ex) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Could not resolve beans DTD [" + systemId + "]: not found in classpath", ex);
                }
            }
        }
    }

    // Fall back to the parser's default behavior.
    return null;
}

解析和注册BeanDefinitions

XmlBeanDefinitionReader

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    //使用DefaultBeanDefinitionDocument实例化BeanDefinitionDocumentReader
    BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    //记录统计前BeanDefinition的加载个数
    int countBefore = getRegistry().getBeanDefinitionCount();
    //加载及注册bean
    documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    //记录本次加载的BeanDefinition个数
    return getRegistry().getBeanDefinitionCount() - countBefore;
}

进入registerBeanDefinitions方法

DefaultBeanDefinitionDocumentReader

@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
    this.readerContext = readerContext;
    //提取DocumentElement
    doRegisterBeanDefinitions(doc.getDocumentElement());
}
protected void doRegisterBeanDefinitions(Element root) {
    BeanDefinitionParserDelegate parent = this.delegate;
    this.delegate = createDelegate(getReaderContext(), root, parent);

    if (this.delegate.isDefaultNamespace(root)) {
        //处理profile属性
        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.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;
}

首先程序会回去beans节点是否定义了profile属性,如果定义了则会需要到环境变量中去寻找,所以这里首先断言environment不可能为空,因为profile是可以同时指定多个的,需要程序对其拆分,并解析每个profile是都符合环境变量中所定义的,不定义则不会浪费性能去解析。

解析并注册BeanDefinition

DefaultBeanDefinitionDocumentReader

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    //对bean的处理
    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 {
                    //对bean的处理
                    delegate.parseCustomElement(ele);
                }
            }
        }
    }
    else {
        delegate.parseCustomElement(root);
    }
}
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);
    }
}

先从bean标签开始

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
        try {
            // Register the final decorated instance.
            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));
    }
}

(1)首先委托BeanDefinitionDelegate类的parseBeanDefinitionElement方法进行元素解析,返回BeanDefinitionHolder类型的实例bdHolder,经过这个方法后, bdHolder实例已经包含我们配置文件中配置的各种属性了,例如class, name,id, alias之类的属性。

(2)当返回的bdHolder不为空的情况下若存在默认标签的子节点下再有自定义属性,还需要再次对自定义标签进行解析。

(3)解析完成后,需要对解析后的bdHolder进行注册,同样,注册操作委托给了BeanDefinitionReaderUtils的registerBeanDefinition方法。

(4)最后发出响应事件,通知想关的监听器,这个bean已经加载完成了。

BeanDefinitionParserDelegate

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
    //解析id属性
    String id = ele.getAttribute(ID_ATTRIBUTE);
    //解析name属性
    String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

    //分割name属性
    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.isTraceEnabled()) {
            logger.trace("No XML 'id' specified - using '" + beanName +
                         "' as bean name and " + aliases + " as aliases");
        }
    }

    if (containingBean == null) {
        checkNameUniqueness(beanName, aliases, ele);
    }
    //进一步解析
    AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
    if (beanDefinition != null) {
        if (!StringUtils.hasText(beanName)) {
            try {
                //如果不存在beanname	那么根据spring命名规则生成对应的beanname
                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.isTraceEnabled()) {
                    logger.trace("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);
        return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
    }

    return null;
}

(1)提取元素中的id以及name属性。

(2)进一步解析其他所有属性并统一封装至GenericBeanDefinition类型的实例中。

(3)如果检测到bean没有指定beanName,那么使用默认规则为此Bean生成beanName

(4)将获取到的信息封装到BeanDefinitionHolder的实例中。

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

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

		String className = null;
		//解析Class属性
		if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
			className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
		}
		String parent = null;
		//解析parent属性
		if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
			parent = ele.getAttribute(PARENT_ATTRIBUTE);
		}

		try {
			//创建用于承载AbstractBeanDefinition类型的GenericBeanDefinition
			AbstractBeanDefinition bd = createBeanDefinition(className, parent);
			//解析默认的bean的各种属性
			parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
			bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));


			//解析元数据
			parseMetaElements(ele, bd);
			//解析lookup-method	属性
			parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
			//解析replace-method属性
			parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
			//解析构造函数参数
			parseConstructorArgElements(ele, bd);
			//解析property子元素
			parsePropertyElements(ele, bd);
			//解析qualifier子元素
			parseQualifierElements(ele, bd);

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

创建用于属性承载的BeanDefinitionBeanDefinition是一个接口,在Spring中存在三种实现: RootBeanDefinition,ChildBeanDefinition以及GenericBeanDefinition。三种实现均继承了AbstractBeanDefiniton ,其中BeanDefinition是配置文件 元素标签在容器中的内部表示形式。 元素标签拥有class, scope, lazy-init等配置属性, BeanDefinition则提供了相应的beanClass, scope, lazylnit属性, BeanDefinition和 中的属性是一一对应的。其中RootBeanDefinition是最常用的实现类,它对应一般性的 元素标签, GenericBeanDefinition是自2.5版本以后新加入的bean文件配置属性定义类,是一站式服务类。在配置文件中可以定义父 和子 ,父 用RootBeanDefinition表示,而子 用ChildBeanDefiniton表示,而没有父 就使用RootBeanDefinition表示。AbstractBeanDefinition对两者共同的类信息进行抽象Spring通过BeanDefinition将配置文件中的 配置信息转换为容器的内部表示,并将这些BeanDefiniton注册到BeanDefinitonRegistry中。Spring容器的BeanDefinitionRegistry就像是Spring配置信息的内存数据库,主要是以map的形式保存,后续操作直接从BeanDefinitionRegistry中读取配置信息。

BeanDefinition

BeanDefinitionParserDelegate

protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName)
    throws ClassNotFoundException {

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

    GenericBeanDefinition bd = new GenericBeanDefinition();
    //parentName可能为空
    bd.setParentName(parentName);
    if (className != null) {
        if (classLoader != null) {
            //如果classLoader不为空,则传入使用的classLoader同一虚拟机加载类对象,否则只是记录classname
            bd.setBeanClass(ClassUtils.forName(className, classLoader));
        }
        else {
            bd.setBeanClassName(className);
        }
    }
    return bd;
}

当我们创建了bean信息的承载实例后,便可以进行bean信息的各种属性解析了,parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);

版权声明
本文为[sunankang]所创,转载请带上原文链接,感谢
https://www.cnblogs.com/sunankang/p/jame.html

Scroll to Top