美文网首页
从最简单的XmlBeanFactory开始读Spring源码(核

从最简单的XmlBeanFactory开始读Spring源码(核

作者: 王侦 | 来源:发表于2022-12-05 23:34 被阅读0次

    示例程序:

    public class BeanFactoryTest {
        @SuppressWarnings(value={"deprecation"})
        public static void main(String[] args) {
            BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("spring-bf.xml"));
            Object a = beanFactory.getBean("componentA");
            Object b = beanFactory.getBean("componentB");
            System.out.println(a);
            System.out.println(b);
        }
    }
    
    <?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="componentA" class="com.wz.spring.xml.ComponentA"/>
        <bean id="componentB" class="com.wz.spring.xml.ComponentB"/>
    </beans>
    

    1.核心流程

        public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
            super(parentBeanFactory);
            this.reader.loadBeanDefinitions(resource);
        }
    

    这里reader是:

    private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
    

    实际加载BeanDefinition是在:

    doLoadBeanDefinitions(inputSource, encodedResource.getResource());
    

    这里核心流程就两步:

    • step1.将xml解析成Document
    • step2.解析并注册BeanDefinition
        protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
                throws BeanDefinitionStoreException {
    
            try {
                Document doc = doLoadDocument(inputSource, resource);
                int count = registerBeanDefinitions(doc, resource);
                if (logger.isDebugEnabled()) {
                    logger.debug("Loaded " + count + " bean definitions from " + resource);
                }
                return count;
            }
    

    2.BeanDefinitionDocumentReader解析并注册BeanDefinition

    核心是BeanDefinitionDocumentReader,会在DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions进行解析处理。

        protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
            // 条件成立:说明root是spring命名空间
            if (delegate.isDefaultNamespace(root)) {
                // <beans>
                //     <bean> ... </bean>
                //     <bean> ... </bean>
                // </beans>
                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;
                        // 子标签也是spring默认标签
                        if (delegate.isDefaultNamespace(ele)) {
                            parseDefaultElement(ele, delegate);
                        }
                        else {
                            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);
            }
        }
    

    import标签示例:

    <?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">
                <import resource="application-business1.xml"/>
                <import resource="application-business2.xml"/>
                <import resource="application-business3.xml"/>
                ...
    </beans>
    

    alias标签示例:

    <bean id="testBean" class="xx.xx.xx.xxBean"/>
    1.要给这个JavaBean增加别名,以方便使用时,我们可以直接使用bean标签中的name属性:
    <bean id="testBean" name="testBean,testBean2" class="xx.xx.xx.xxBean"/>
    2.Spring还提供了 另外一种声明别名的方式:
    <bean id="testBean" class="xx.xx.xx.xxBean"/>
    <alias name="testBean" alias="testBean,testBean2"/>
    

    处理bean标签:

        protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
            // 这里处理了bean名字以及解析AbstractBeanDefinition
            BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
            if (bdHolder != null) {
                // 这里进行装饰,主要处理自定义属性
                bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
                try {
                    // Register the final decorated instance.
                    // 将bd注册到容器里面
                    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));
            }
        }
    

    BeanDefinitionParserDelegate#parseBeanDefinitionElement的方法:

    • 1)将name拆分成数组,作为别名
    • 2)id没有值且别名不为空,则将别名第一个名字作为beanName
    • 3)解析AbstractBeanDefinition
    • 4)如果beanName为空,会生成一个beanName:className#序列号
    • 5)如果className没有使用,则加一个别名为className别名

    注意别名的注册,是放在aliasMap中ConcurrentHashMap,key - alias,value - beanName。

    核心在重载方法BeanDefinitionParserDelegate#parseBeanDefinitionElement()处理BeanDefinition:

        public AbstractBeanDefinition parseBeanDefinitionElement(
                Element ele, String beanName, @Nullable BeanDefinition containingBean) {
    
            this.parseState.push(new BeanEntry(beanName));
    
            String className = null;
            // 读取bean标签的className,除非从parent标签继承
            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 {
                // 创建bd对象,设置beanClass或者beanClassName
                AbstractBeanDefinition bd = createBeanDefinition(className, parent);
    
                // 解析attribute信息:scope、lazy-init、init-method、depends-on等
                parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
                // description
                bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
    
                // meta
                parseMetaElements(ele, bd);
                // lookup-method
                parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
                // replaced-method
                parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
    
                // 解析constructor-arg子元素
                parseConstructorArgElements(ele, bd);
                // 解析property子元素
                parsePropertyElements(ele, bd);
                // 解析qualifier子元素
                parseQualifierElements(ele, bd);
    
                bd.setResource(this.readerContext.getResource());
                bd.setSource(extractSource(ele));
    
                return bd;
            }
    

    注意property或者constructor-arg解析时:

    • 1)ref和value不能同时存在
    • 2)ref或value有一个存在时,就不能有子元素subElement

    正好对应Bean的xml配置:

    <bean id="xxxComponent" name="xxxComponent" class="xx.xx.xx.xxxComponent">
        <meta key="meta_1" value="meta_val_1"/>
        <meta key="meta_2" value="meta_val_2"/>
        ...
        
        <property name="key1" value="value1"/>
        <property name="key2" value="value2"/>
        ...
        
        
        <constructor-arg index="0">
            <value>aaa</value>
        </constructor-arg>
        <constructor-arg index="1">
            <value>bbb</value>
        </constructor-arg>
        <constructor-arg index="2">
            <map>
                <entry key="key" value="value">
                ...
            </map>
        </constructor-arg>
        
    </bean>
    

    重点来看看BeanDefinitionParserDelegate#parseBeanDefinitionAttributes

        public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
                @Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {
    
            // scope属性的处理
            if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
                error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
            }
            else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
                bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
            }
            else if (containingBean != null) {
                // Take default from containing bean in case of an inner bean definition.
                bd.setScope(containingBean.getScope());
            }
    
            // abstract为true,表示是一个抽象bean,只能让子bean去继承
            if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
                bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
            }
    
            // lazy-init
            String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
            if (isDefaultValue(lazyInit)) {
                lazyInit = this.defaults.getLazyInit();
            }
            bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
    
            // autowire值
            String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
            bd.setAutowireMode(getAutowireMode(autowire));
    
            // depends-on
            if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
                String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
                bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
            }
    
            // autowire-candidate设置为false后,当前bean不能参与其余bean的自动依赖注入。默认是true。
            String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
            if (isDefaultValue(autowireCandidate)) {
                String candidatePattern = this.defaults.getAutowireCandidates();
                if (candidatePattern != null) {
                    String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
                    bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
                }
            }
            else {
                bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
            }
    
            // primary,依赖注入有多个候选对象,选择primary
            if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
                bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
            }
    
            // init-method
            if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
                String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
                bd.setInitMethodName(initMethodName);
            }
            else if (this.defaults.getInitMethod() != null) {
                bd.setInitMethodName(this.defaults.getInitMethod());
                bd.setEnforceInitMethod(false);
            }
    
            // destroy-method
            if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
                String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
                bd.setDestroyMethodName(destroyMethodName);
            }
            else if (this.defaults.getDestroyMethod() != null) {
                bd.setDestroyMethodName(this.defaults.getDestroyMethod());
                bd.setEnforceDestroyMethod(false);
            }
    
            // factory-method
            if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
                bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
            }
            // factory-bean
            if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
                bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
            }
    
            return bd;
        }
    

    3.继承体系


    4.Spring IOC容器架构图

    相关文章

      网友评论

          本文标题:从最简单的XmlBeanFactory开始读Spring源码(核

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