Spring source code analysis (2) How does Spring extend and parse the xml interface

Custom Spring Configuration

https://blog.csdn.net/bingduanlbd/article/details/38770685

BeanDefinitionParserDelegate


When the DefaultBeanDefinitionDocumentReader processes the Document element, it delegates the specific parsing work of the elements in the Document document to the BeanDefinitionParserDelegate class for processing. The default BeanDefinitionParserDelegate will process the elements and their properties under the " http://www.springframework.org/schema/beans " namespace, see In the source code, you can see that a bunch of element and attribute names are defined under BeanDefinitionParserDelegate. These element and attribute names can be found in the class respectively.

public class BeanDefinitionParserDelegate {

    public static final String BEANS_NAMESPACE_URI = "http://www.springframework.org/schema/beans";

    public static final String MULTI_VALUE_ATTRIBUTE_DELIMITERS = ",; ";
    private final XmlReaderContext readerContext;

    private final DocumentDefaultsDefinition defaults = new DocumentDefaultsDefinition();
    /**
    *初始化 default lazy-init, autowire, dependency check settings,
    * init-method, destroy-method and merge settings等属性值
    * 并且填充到属性 DocumentDefaultsDefinition defaults;
    * 如果 当前Xml文件没有配置默认属性,则查父类delegate有没有设置属性;如果没有则 使用默认配置
    */
    protected void populateDefaults(DocumentDefaultsDefinition defaults, DocumentDefaultsDefinition parentDefaults, Element root) {
        String lazyInit = root.getAttribute(DEFAULT_LAZY_INIT_ATTRIBUTE);
        if (DEFAULT_VALUE.equals(lazyInit)) {
            // Potentially inherited from outer <beans> sections, otherwise falling back to false.
            lazyInit = (parentDefaults != null ? parentDefaults.getLazyInit() : FALSE_VALUE);
        }
        defaults.setLazyInit(lazyInit);

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

        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));
    }
    //解析自定义元素
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
        //获取当前Element的命名空间
        String namespaceUri = getNamespaceURI(ele);
        //获取namespaceHandlerResolver然后根据命名空间得到具体的 NamespaceHandler处理类
        NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
        if (handler == null) {
            error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
            return null;
        }
        //具体的NamespaceHandler处理类去解析Element;返回 BeanDefinition 对象
        return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
    }
    //返回defaults属性值
    public BeanDefinitionDefaults getBeanDefinitionDefaults() {
        BeanDefinitionDefaults bdd = new BeanDefinitionDefaults();
        bdd.setLazyInit("TRUE".equalsIgnoreCase(this.defaults.getLazyInit()));
        bdd.setDependencyCheck(this.getDependencyCheck(DEFAULT_VALUE));
        bdd.setAutowireMode(this.getAutowireMode(DEFAULT_VALUE));
        bdd.setInitMethodName(this.defaults.getInitMethod());
        bdd.setDestroyMethodName(this.defaults.getDestroyMethod());
        return bdd;
    }

DefaultNamespaceHandlerResolver


DefaultNamespaceHandlerResolver implements NamespaceHandlerResolver;
the default namespace resolution object selector; the main function is to select the corresponding resolver according to different namespaces;

    /**
     * Locate the {@link NamespaceHandler} for the supplied namespace URI
     * from the configured mappings.
     * @param namespaceUri the relevant namespace URI
     * @return the located {@link NamespaceHandler}, or {@code null} if none found
     */
    @Override
    public NamespaceHandler resolve(String namespaceUri) {
        Map<String, Object> handlerMappings = getHandlerMappings();
        Object handlerOrClassName = handlerMappings.get(namespaceUri);
        if (handlerOrClassName == null) {
            return null;
        }
        //如果已经把全类名路径转换成具体的实例了  就直接返回
        else if (handlerOrClassName instanceof NamespaceHandler) {
            return (NamespaceHandler) handlerOrClassName;
        }
        else {

            String className = (String) handlerOrClassName;
            try {
               //根据全类名路径 来加载这个类
                Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
                if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
                    throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
                            "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
                }
                //加载完类之后,通过反射生成具体实例对象;例如:ContextNamespaceHandler
                NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
                //调用具体对象的init()方法,注册对应的解析类,例如annotation-config 对应的解析类是 AnnotationConfigBeanDefinitionParser
                namespaceHandler.init();
                //将实例对象覆盖 全类名路径
                handlerMappings.put(namespaceUri, namespaceHandler);
                return namespaceHandler;
            }
            catch (ClassNotFoundException ex) {
                throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" +
                        namespaceUri + "] not found", ex);
            }
            catch (LinkageError err) {
                throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" +
                        namespaceUri + "]: problem with handler class file or dependent class", err);
            }
        }
    }



     /**
     * 第一次加载的时候 Map里面的对象 是String类型,全类名路径
     */
    private Map<String, Object> getHandlerMappings() {
        if (this.handlerMappings == null) {
            synchronized (this) {
                if (this.handlerMappings == null) {
                        //加载META-INF/spring.handlers的所有属性
                        Properties mappings =
                                PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
                        if (logger.isDebugEnabled()) {
                            logger.debug("Loaded NamespaceHandler mappings: " + mappings);
                        }
                        Map<String, Object> handlerMappings = new ConcurrentHashMap<String, Object>(mappings.size());
                        CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
                        this.handlerMappings = handlerMappings;
                    }
                    catch (IOException ex) {
                        throw new IllegalStateException(
                                "Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);
                    }
                }
            }
        }
        return this.handlerMappings;
    }

NamespaceHandlerSupport implements NamespaceHandler


Implements the parse() and decorate methods in NamespaceHandler, and provides some properties to maintain the object BeanDefinitionParser of specific parsed elements;
for example: The operation class corresponding to the http://www.springframework.org/schema/context namespace is ContextNamespaceHandler;
This action class will call the init() method

@Override
    public void init() {
        registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
        registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
        registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
        registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
        registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
        registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
        registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
        registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
    }

Register different parsing classes BeanDefinitionParser according to different properties
write picture description here

Let's take a look at ContextNamespaceHandler. The implementation class only needs to implement the init method; the corresponding parsing class is stored in the Map parsers in NamespaceHandlerSupport through the registerBeanDefinitionParser method.
write picture description here

public abstract class NamespaceHandlerSupport implements NamespaceHandler {
        //将元素头 与对应的解析器对应起来
        protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {
            this.parsers.put(elementName, parser);
        }

    /**
    *具体的NamespaceHandler处理类去解析Element;返回 BeanDefinition 对象
    * BeanDefinitionParserDelegate.parseCustomElement 中 在获取到了对应的handler后,会执行handler.parse(ele, new ParserContext(this.readerContext, this, containingBd))方法;
    * 例如:获取到的操作类是  ContextNamespaceHandler,调用parse的方法其实调用了NamespaceHandlerSupportde parse方法;也就是下面的 
    * 例如annotation-config得到的是AnnotationConfigBeanDefinitionParser实例, 再调用AnnotationConfigBeanDefinitionParser的parse方法;这样就实现了根据不同元素来解析成 Spring中的 定义Bean BeanDefinition了;
    */
    @Override
    public BeanDefinition parse(Element element, ParserContext parserContext) {
        return findParserForElement(element, parserContext).parse(element, parserContext);
    }

    /**
     * 根据元素节点的名称 获取对应的解析类实例;例如annotation-config得到的是AnnotationConfigBeanDefinitionParser实例,
     */
    private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
        String localName = parserContext.getDelegate().getLocalName(element);
        BeanDefinitionParser parser = this.parsers.get(localName);
        if (parser == null) {
            parserContext.getReaderContext().fatal(
                    "Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
        }
        return parser;
    }


}
public class ContextNamespaceHandler extends NamespaceHandlerSupport {

    @Override
    public void init() {
        registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
        registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
        registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
        registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
        registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
        registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
        registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
        registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
    }

}

BeanDefinitionParser


The parsing class of the Element element; there is only one method BeanDefinition parse(Element element, ParserContext parserContext);
the implementation class needs to implement this method;

We see that the ParserContext parameter is passed in the parse method ; let's take a look at this;

ParserContext


Parse class context; this type holds XmlReaderContext and BeanDefinitionParserDelegate; it allows users to parse by themselves to the greatest extent

    public ParserContext(XmlReaderContext readerContext, BeanDefinitionParserDelegate delegate,
            BeanDefinition containingBeanDefinition) {

        this.readerContext = readerContext;
        this.delegate = delegate;
        this.containingBeanDefinition = containingBeanDefinition;
    }

Guess you like

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