Sring source code analysis (1) How does Spring read the configuration Xml file

Spring reads configuration file

Document


XmlBeanDefinitionReader.doLoadBeanDefinitions(InputSource inputSource, Resource resource)Convert the Xml file to a Document object in the method;
Document doc = doLoadDocument(inputSource, resource);
write picture description here

Element


org.w3c.dom.Element is an interface public interface Element extends Node
Spring in DefaultBeanDefinitionDocumentReader

    @Override
    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
        this.readerContext = readerContext;
        logger.debug("Loading bean definitions");
        // 从Document中获取Element
        Element root = doc.getDocumentElement();
        //注册BeanDefinitions
        doRegisterBeanDefinitions(root);
    }

in DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(Element root)_

protected void doRegisterBeanDefinitions(Element root) {
        BeanDefinitionParserDelegate parent = this.delegate;

        /**
        1.根据Element root创建**BeanDefinitionParserDelegate**对象
        2.解析Xml文件头中的一些属性配置到 BeanDefinitionParserDelegate属性(DocumentDefaultsDefinition)defaults;
        **/
        this.delegate = createDelegate(getReaderContext(), root, parent);
        //根据root查询 xml文件的命名空间是不是public static final String BEANS_NAMESPACE_URI = "http://www.springframework.org/schema/beans";
        if (this.delegate.isDefaultNamespace(root)) {
            //省略.....
        }
        //默认空实现 子类可以重写这个方法来处理自定义xml文件
        preProcessXml(root);
        parseBeanDefinitions(root, this.delegate);
        //默认空实现 子类可以重写这个方法来处理自定义xml文件
        postProcessXml(root);

        this.delegate = parent;
    }

this.delegate = createDelegate(getReaderContext(), root, parent);Inside call BeanDefinitionParserDelegate.initDefaults method
1. Initialize property value 2. TODO…private final DocumentDefaultsDefinition defaults = new DocumentDefaultsDefinition();

public void initDefaults(Element root, BeanDefinitionParserDelegate parent) {
        // this.defaults 是一个DocumentDefaultsDefinition对象;
        populateDefaults(this.defaults, (parent != null ? parent.defaults : null), root);
        this.readerContext.fireDefaultsRegistered(this.defaults);
    }

The BeanDefinitionParserDelegate.populateDefaults method is mainly to convert the basic configuration of some namespaces in the xml file into DocumentDefaultsDefinition objects;
for example

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd"
    default-autowire="byName" default-lazy-init="false" default-dependency-check="all" >
//parentDefaults是父类的DocumentDefaultsDefinition对象
protected void populateDefaults(DocumentDefaultsDefinition defaults, DocumentDefaultsDefinition parentDefaults, Element root) {
        //查看xml文件中默认的default-lazy-init 值;(如果xml没有显示配置 则它的值为 default)懒加载的默认值
        String lazyInit = root.getAttribute(DEFAULT_LAZY_INIT_ATTRIBUTE);
        if (DEFAULT_VALUE.equals(lazyInit)) {
            //如果有父类,则以父类的为准,否则将返回false。
            lazyInit = (parentDefaults != null ? parentDefaults.getLazyInit() : FALSE_VALUE);
        }
        defaults.setLazyInit(lazyInit);
        //default-autowire-candidates
        String merge = root.getAttribute(DEFAULT_MERGE_ATTRIBUTE);
        if (DEFAULT_VALUE.equals(merge)) {
            // Potentially inherited from outer <beans> sections, otherwise falling back to false.
            merge = (parentDefaults != null ? parentDefaults.getMerge() : FALSE_VALUE);
        }
        defaults.setMerge(merge);
        //default-autowire
        String autowire = root.getAttribute(DEFAULT_AUTOWIRE_ATTRIBUTE);
        if (DEFAULT_VALUE.equals(autowire)) {
            // Potentially inherited from outer <beans> sections, otherwise falling back to 'no'.
            autowire = (parentDefaults != null ? parentDefaults.getAutowire() : AUTOWIRE_NO_VALUE);
        }
        defaults.setAutowire(autowire);

        // Don't fall back to parentDefaults for dependency-check as it's no longer supported in
        // <beans> as of 3.0. Therefore, no nested <beans> would ever need to fall back to it.
        defaults.setDependencyCheck(root.getAttribute(DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE));

        if (root.hasAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE)) {
            defaults.setAutowireCandidates(root.getAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE));
        }
        else if (parentDefaults != null) {
            defaults.setAutowireCandidates(parentDefaults.getAutowireCandidates());
        }

        if (root.hasAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)) {
            defaults.setInitMethod(root.getAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE));
        }
        else if (parentDefaults != null) {
            defaults.setInitMethod(parentDefaults.getInitMethod());
        }

        if (root.hasAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE)) {
            defaults.setDestroyMethod(root.getAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE));
        }
        else if (parentDefaults != null) {
            defaults.setDestroyMethod(parentDefaults.getDestroyMethod());
        }
        //这里是???
        defaults.setSource(this.readerContext.extractSource(root));
    }

DocumentDefaultsDefinition


DocumentDefaultsDefinition (document default value definition) holds the properties of the {@code beans} level in the standard Spring Xml file, these properties are the default global property values ​​in the current Xml configuration, such as { @code default-lazy-init }, { @code default-autowire }, etc.

E.g:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd"
    default-autowire="byName" default-lazy-init="false" default-dependency-check="all" >

DefaultsDefinition


The default defined markup interface, without any definition, just simply mark it; inherit the BeanMetadataElement class; usually the specific implementation (such as DocumentDefaultsDefinition) is based on the default value of the document, such as setting the default value at the root tag level of an XML document

BeanMetadataElement

The metadata interface that needs to be implemented, this interface defines the Object getSource() method, which returns a configuration source object

public class DocumentDefaultsDefinition implements DefaultsDefinition {
    //初始化懒加载
    private String lazyInit;
    //
    private String merge;
    // 自动装载的类型 
    private String autowire;
    //
    private String dependencyCheck;

    private String autowireCandidates;
    //初始化方法
    private String initMethod;
    //销毁方法
    private String destroyMethod;
    //返回配置源对象
    private Object source;
    //省略 get set ......
}

Optional values ​​for default-autowire and autowire

optional value Function Description
no Autowiring is not used by default. The bean must be specified explicitly using the "" tag.
byName Autowire based on property name. This option will check the container and find a bean that matches the property exactly by name, and autowire it with the property.
byType If a bean of the same type as the specified property exists in the container, it will be autowired with that property. If there is more than one bean of this type, an exception will be thrown stating that autowiring cannot be done using the byType method. If no matching bean is found, nothing happens and the property is not set. If you don't want this, you can have Spring throw an exception by setting dependency-check=”objects”.
constructor Similar to the way byType, except that it applies to constructor arguments. If no bean of the same type as the constructor parameter is found in the container, an exception will be thrown.
autodetect The introspection mechanism of the bean class is used to decide whether to use the constructor or byType for automatic assembly. If a default constructor is found, the byType method will be used.

After parsing some default attributes of Element in xml, the next step is to parse the sub-attributes in Element. In
DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(root, this.delegate);
this method, we mainly look atdelegate.parseCustomElement(ele);

    public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
        //获取命名空间
        String namespaceUri = getNamespaceURI(ele);
        //根据命名空间得到命名空间的处理类handler  如果是dubbo的uri 则返回的就是DubboNamespaceHandler
        //他们都继承自NamespaceHandlerSupport implements NamespaceHandler 
        //里面有调用了hander的init()...
        NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
        if (handler == null) {
            error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
            return null;
        }
        //1.根据Element的getLocalName()得到Element的name,然后根据这个name去NamespaceHandlerSupport中的一个属性为private final Map<String, BeanDefinitionParser> parsers ;中查找对应的解析器;这个解析器是什么时候被放到这个map里面的呢?TODO...
        //2.根据对应的解析器调用  .parse(element,parserContext)进行解析   
        return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
    }

Let's parse it separately.
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri)
First , let's understand that it this.readerContextis a property in BeanDefinitionParserDelegate
private final XmlReaderContext readerContext;

XmlReaderContext


Inherits the ReaderContext class and provides access to XmlBeanDefinitionReader and NamespaceHandlerResolver ;

public class XmlReaderContext extends ReaderContext {
    //可以看到 方法权限是private 的
    private final XmlBeanDefinitionReader reader;
    private final NamespaceHandlerResolver namespaceHandlerResolver;
    public XmlReaderContext(
            Resource resource, ProblemReporter problemReporter,
            ReaderEventListener eventListener, SourceExtractor sourceExtractor,
            XmlBeanDefinitionReader reader, NamespaceHandlerResolver namespaceHandlerResolver) {

        super(resource, problemReporter, eventListener, sourceExtractor);
        this.reader = reader;
        this.namespaceHandlerResolver = namespaceHandlerResolver;
    }
    //但是提供了一些访问的方法
    public final XmlBeanDefinitionReader getReader() {
        return this.reader;
    }
    public final BeanDefinitionRegistry getRegistry() {
        return this.reader.getRegistry();
    }
    public final ResourceLoader getResourceLoader() {
        return this.reader.getResourceLoader();
    }
    public final ClassLoader getBeanClassLoader() {
        return this.reader.getBeanClassLoader();
    }
    public final Environment getEnvironment() {
        return this.reader.getEnvironment();
    }
    public final NamespaceHandlerResolver getNamespaceHandlerResolver() {
        return this.namespaceHandlerResolver;
    }
        public String generateBeanName(BeanDefinition beanDefinition) {
        return this.reader.getBeanNameGenerator().generateBeanName(beanDefinition, getRegistry());
    }
    public String registerWithGeneratedName(BeanDefinition beanDefinition) {
        String generatedName = generateBeanName(beanDefinition);
        getRegistry().registerBeanDefinition(generatedName, beanDefinition);
        return generatedName;
    }
    public Document readDocumentFromString(String documentContent) {
        InputSource is = new InputSource(new StringReader(documentContent));
        try {
            return this.reader.doLoadDocument(is, getResource());
        }
        catch (Exception ex) {
            throw new BeanDefinitionStoreException("Failed to read XML document", ex);
        }
    }

1. When is XmlReaderContext assigned? Let's take a look at XmlReaderContext
①.
Created in XmlBeanDefinitionReader.registerBeanDefinitions

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        int countBefore = getRegistry().getBeanDefinitionCount();
        //创建XmlReaderContext,然后赋值给BeanDefinitionDocumentReader中readerContext属性中
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        return getRegistry().getBeanDefinitionCount() - countBefore;
    }
public XmlReaderContext createReaderContext(Resource resource) {
        //this 最后就是 XmlReaderContext中的XmlBeanDefinitionReader属性
        return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
                this.sourceExtractor, this, getNamespaceHandlerResolver());
    }
    public NamespaceHandlerResolver getNamespaceHandlerResolver() {
        if (this.namespaceHandlerResolver == null) {
            this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver();
        }
        return this.namespaceHandlerResolver;
    }
    /**
    *如果没有具体的实现类,则创建 默认的实现类返回
    * 默认的实现类DefaultNamespaceHandlerResolver中的handlerMappingsLocation属性(Resource location to search for)=META-INF/spring.handlers
    */
    protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() {
        return new DefaultNamespaceHandlerResolver(getResourceLoader().getClassLoader());
    }

②. The created XmlReaderContext is used as a parameter of the BeanDefinitionParserDelegate constructor to create a BeanDefinitionParserDelegate object

protected void doRegisterBeanDefinitions(Element root) {
        BeanDefinitionParserDelegate parent = this.delegate;
        this.delegate = createDelegate(getReaderContext(), root, parent); 
        //省略.....
        }

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325894826&siteId=291194637