美文网首页
spring加载配置

spring加载配置

作者: binecy | 来源:发表于2017-12-22 14:35 被阅读47次

    源码分析基于spring 4.3.x

    本文通过阅读源码,分析spring加载配置文件的过程

    小栗子

    bean类

    public class Blog {
        private String title;
    
        ... getter and settter
    }
    

    spring.xml配置

        <bean id="blog" class="spring.bean.Blog">
            <property name="title" value="hello spring"></property>
        </bean>
    

    测试方法

        @Test
        public void test() {
            BeanFactory xmlBeanFactory = new XmlBeanFactory(new ClassPathResource("spring.xml"));
            Blog bean = (Blog)xmlBeanFactory.getBean("blog");
    
            Assert.assertEquals(bean.getTitle(), "hello spring");
        }
    

    解析

    XmlBeanFactory继承于DefaultListableBeanFactoryDefaultListableBeanFactory是整个bean加载的核心部分,是Spring注册及加载的bean的默认实现。 XmlBeanFactory只是使用了自定义的XML读取器XmlBeanDefinitionReader

    但本篇文章就关注XmlBeanDefinitionReader

    跟踪XmlBeanFactory的构造方法,

    
    private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
    public /home/binecy/work/bin-learning(Resource resource, BeanFactory parentBeanFactory) ... {
        super(parentBeanFactory);
        this.reader.loadBeanDefinitions(resource);  // 注:this.reader为XmlBeanDefinitionReader
    }
    

    接口结构

    reader.png

    XmlBeanFactory实现了BeanDefinitionRegistry, 可以将beanDefinition注册到spring环境
    XmlBeanDefinitionReader实现了BeanDefinitionReader, 实现核心方法loadBeanDefinitions, 该方法复制读取xml文件,并加载到spring中, 是spring加载配置的核心。
    BeanDefinitionReader中有一个关键属性BeanDefinitionRegistry, 这里就是XmlBeanFactory(XmlBeanDefinitionReader构造参数的this就是XmlBeanFactory)

    这里会调用到XmlBeanDefinitionReader.loadBeanDefinitions方法:

    public int loadBeanDefinitions(EncodedResource encodedResource)  {  
        //获取配置文件的InputStream
        InputStream inputStream = encodedResource.getResource().getInputStream();   
            try {
            // 构造InputSource
            InputSource inputSource = new InputSource(inputStream); 
            // 解析InputSource
            return doLoadBeanDefinitions(inputSource, encodedResource.getResource());   
          }
          finally {
                inputStream.close();
        }  
    }
    
    // 查看 解析过程 
    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)  {
        // 获取Document对象
        Document doc = doLoadDocument(inputSource, resource);   
        // 解析Document并注册到spring
        return registerBeanDefinitions(doc, resource);  
    }  
    
    // 查看Document解析过程
    public int registerBeanDefinitions(Document doc, Resource resource) {
        // 创建DefaultBeanDefinitionDocumentReader对象
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); 
        // 解析documentReader
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); 
    }
    

    先看一下createReaderContext

    public XmlReaderContext createReaderContext(Resource resource) {
        return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
                this.sourceExtractor, this, getNamespaceHandlerResolver());
    }
    

    XmlReaderContext就是一个上下文, 这里把this(就是XmlBeanDefinitionReader), resource等信息放到了这个上下文中。

    再看看BeanDefinitionDocumentReader, 他是一个简单的接口, 只有一个方法registerBeanDefinitions和一个实现类DefaultBeanDefinitionDocumentReader, 但对xml的解析基本都在这个类了:

    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
        // 获取root元素
        Element root = doc.getDocumentElement();    
        // 解析root元素
        doRegisterBeanDefinitions(root);    
    }
       
    protected void doRegisterBeanDefinitions(Element root) {
        // 创建BeanDefinitionParserDelegate对象
        this.delegate = createDelegate(getReaderContext(), root, parent);   
        preProcessXml(root);    // 模板方法,提供给子类扩展
        parseBeanDefinitions(root, this.delegate);      // 解析root元素
        postProcessXml(root);   // 模板方法,提供给子类扩展
    }
      
    protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        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); // 解析node结点
                    }
                    else {
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        }
        else {
            delegate.parseCustomElement(root);
        }
    }
    

    上述方法根据Namespace Uri判断node是否为Spring定义的元素,如果是,则调用parseDefaultElement方法解析元素。否则调用自定义的解析方法。
    用户可以自定义标签及标签解析器, 文章最后会提到。

    下面看看默认的解析方法:

        private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
            if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { // 解析import标签
                importBeanDefinitionResource(ele);
            }
            else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { // 解析alias标签
                processAliasRegistration(ele);
            }
            else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {  // 解析bean标签
                processBeanDefinition(ele, delegate);
            }
            else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {  // 解析beans标签
                doRegisterBeanDefinitions(ele);
            }
        }
    

    parseDefaultElement方法对import,alias,bean,beans标签进行了解析,这里主要看bean的解析过程:

    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        // 解析元素,解析结果为BeanDefinitionHolder对象
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);   
        if (bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);    // 装饰模式
            
            // 注册BeanDefinition,即将解析结果存储在registry对象中.
            BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder,getReaderContext().getRegistry());    
            
            // 发送事件
            getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }
    }
    

    这里出现了一个很重要的角色BeanDefinition。

    BeanDefinition是spring对bean的抽象, 是配置文件中<bean>标签在spring容器中的内部表示类, 存储了bealn的相关信息, 如属性PropertyValues, BeanClassName,Scope等

    beanDefinition.png

    BeanDefinition有两个实现类ChildBeanDefinition和RootBeanDefinition。

    BeanDefinition存在子类RootBeanDefinition和ChildBeanDefinition。
    ChildBeanDefinition表示child <bean>, child <bean>parent中继承父类的构造函数参数值,属性值和方法覆盖,并且可以添加新的值。
    RootBeanDefinition表示没有parent的bean

    spring会将配置文件中<bean>配置信息转化为beanDefinition对象,并注册到容器中。

    BeanDefinitionHolder中持有BeanDefinition实例, 同时附带了beanName和aliases属性。

    回来看看delegate.parseBeanDefinitionElement,这里调用BeanDefinitionParserDelegate.parseBeanDefinitionElement方法:

    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
        // 解析bean元素
        AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
    
        String beanClassName = beanDefinition.getBeanClassName();
    
        String[] aliasesArray = StringUtils.toStringArray(aliases);
        return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
    }
    
    // 查看bean元素的解析过程
    public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean) {        
        className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); // 解析className
    
        parent = ele.getAttribute(PARENT_ATTRIBUTE);
    
    
        AbstractBeanDefinition bd = createBeanDefinition(className, parent);
    
        parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);   // 解析"scope","scope"等属性
        bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
    
        parseMetaElements(ele, bd); // 解析meta属性
        parseLookupOverrideSubElements(ele, bd.getMethodOverrides());   // 处理lookup-method元素
        parseReplacedMethodSubElements(ele, bd.getMethodOverrides());   // 处理replaced-method元素
    
        parseConstructorArgElements(ele, bd);   // 解析constructor-arg构造方法参数
        parsePropertyElements(ele, bd); // 解析property元素
        parseQualifierElements(ele, bd);    //解析qualifier元素
    
        bd.setResource(this.readerContext.getResource());
        bd.setSource(extractSource(ele));
    
        return bd;
    }
    

    看一下属性的解析过程parsePropertyElements

    public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
        NodeList nl = beanEle.getChildNodes();
        for (int i = 0; i < nl.getLength(); i++) {
            Node node = nl.item(i);
            // 如果是property节点就解析
            if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
                parsePropertyElement((Element) node, bd);
            }
        }
    }
    
    // 解析property节点
    public void parsePropertyElement(Element ele, BeanDefinition bd) {
        String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
        // 解析property节点Value
        Object val = parsePropertyValue(ele, bd, propertyName);
        PropertyValue pv = new PropertyValue(propertyName, val);
        parseMetaElements(ele, pv);
        pv.setSource(extractSource(ele));
        // 解析结果添加到BeanDefinition 
        bd.getPropertyValues().addPropertyValue(pv);        
    }
    
    // 解析property节点的Value
    public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {
        boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
        boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
    
        if (hasRefAttribute) {  // 如果有ref属性
            String refName = ele.getAttribute(REF_ATTRIBUTE);
            
            RuntimeBeanReference ref = new RuntimeBeanReference(refName);
            ref.setSource(extractSource(ele));
            return ref;
        }
        else if (hasValueAttribute) {       // 如果有value属性
            TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
            valueHolder.setSource(extractSource(ele));
            return valueHolder;
        } else if (subElement != null) {
            // 如果有子标签,如list,set
            return parsePropertySubElement(subElement, bd);
        }
        ...
    }
    

    可以看到,解析property节点主要解析它ref属性(结果为RuntimeBeanReference)或value属性(结果为TypedStringValue)或子标签,并将结果添加到BeanDefinition 中,供spring生成bean时使用。

    可以看看子标签的解析

    public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) {
        if (!isDefaultNamespace(ele)) {
            return parseNestedCustomElement(ele, bd);
        }
        else if (nodeNameEquals(ele, BEAN_ELEMENT)) {
            ...
        }
        else if (nodeNameEquals(ele, REF_ELEMENT)) {
            ...
        }
        else if (nodeNameEquals(ele, IDREF_ELEMENT)) {
            return parseIdRefElement(ele);
        }
        else if (nodeNameEquals(ele, VALUE_ELEMENT)) {
            return parseValueElement(ele, defaultValueType);
        }
        ...
    }
    

    可以看到,这里对各种类型的子标签(bean,ref,array,list等)进行了解析。这里不再对每一类型的子标签展开了。

    最后看一下注册过程BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());

    public static void registerBeanDefinition(
            BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) ...{
    
        // 为bean注册beanName
        String beanName = definitionHolder.getBeanName();
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    
        // 为bean注册别名
        String[] aliases = definitionHolder.getAliases();
        if (aliases != null) {
            for (String alias : aliases) {
                registry.registerAlias(beanName, alias);
            }
        }
    }
            
    

    getReaderContext().getRegistry()获取到XmlBeanFactory, registry.registerBeanDefinition最终将调用到DefaultListableBeanFactory.registerBeanDefinition方法:

        @Override
        public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) ... {
            this.beanDefinitionMap.put(beanName, beanDefinition);
    
        }   
    

    最后,bean解析结果beanDefinition存储在DefaultListableBeanFactory的beanDefinitionMap属性中(实际上就是map对象)。

    最后, 再看一下自定义标签的处理, 将调用BeanDefinitionParserDelegate.parseCustomElement

    public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
        String namespaceUri = getNamespaceURI(ele);
        // 获取对应的NamespaceHandler
        NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
        // 调用NamespaceHandler处理
        return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
    }
    

    这里可以看到, 自定义标签主要使用自定义的NamespaceHandler进行处理。

    相关文章

      网友评论

          本文标题:spring加载配置

          本文链接:https://www.haomeiwen.com/subject/fdstgxtx.html