Spring源码分析3 — spring XML配置文件的解析流程

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】

1 介绍

创建并初始化spring容器中,关键一步就是读取并解析spring XML配置文件。这个过程比较复杂,本文将详细分析整个流程。先看涉及到的关键类。

XmlWebApplicationContext:web应用的默认Spring容器

XmlBeanDefinitionReader:读取XML并解析xml文件

DocumentLoader:文件先被读取为了原始的输入流InputStream,然后封装为InputSource。DocumentLoader加载inputSource,解析后得到Document对象

Document:代表一个XML或者HTML标记文件,包含docType,各种element节点等。

BeanDefinition:XML中bean在spring容器中的表示。Document会被解析为BeanDefinition。在Bean创建和初始化中它们会大展拳脚。

BeanDefinitionDocumentReader:解析Document中的节点元素Element,转换为BeanDefinition,并注册他们到BeanDefinition注册表中。默认实现类为DefaultBeanDefinitionDocumentReader

BeanDefinitionParserDelegate:实际解析Document中的节点元素,采用了代理模式。

2 流程

2.1 obtainFreshBeanFactory

初始化spring容器中的refresh()方法中,会调用obtainFreshBeanFactory()方法,它是读取并解析spring xml配置文件的入口。详细过程可以参看上一篇文章。下面从这个方法开始分析。

    // obtainFreshBeanFactory 加载spring XML配置文件
    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
       // 关键所在,后面分析
       refreshBeanFactory();
       // log之类的东西,不是很关键了
       ConfigurableListableBeanFactory beanFactory = getBeanFactory();
       if (logger.isDebugEnabled()) {
          logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
       }
       return beanFactory;
    }
    protected final void refreshBeanFactory() throws BeansException {
       // BeanFactory已存在,则先销毁它
       if (hasBeanFactory()) {
          destroyBeans();
          closeBeanFactory();
       }
       try {
         // new DefaultListableBeanFactory,创建容器,设置id,个性化配置等
          DefaultListableBeanFactory beanFactory = createBeanFactory();
          beanFactory.setSerializationId(getId());
          customizeBeanFactory(beanFactory);
         // 加载xml配置文件,具体子ApplicationContext会实现它。不同子类实现会不同。重点节点,后面分析
          loadBeanDefinitions(beanFactory);
          synchronized (this.beanFactoryMonitor) {
             this.beanFactory = beanFactory;
          }
       }
       catch (IOException ex) {
          throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
       }
    }

2.2 loadBeanDefinitions

下面我们来分析web应用中默认的spring容器,也就是XmlWebApplicationContext,中的loadBeanDefinitions。

通过XmlBeanDefinitionReader来读取xml配置文件。

    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
       // 创建XmlBeanDefinitionReader,用它来读取XML配置文件
       XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

       // 配置beanDefinitionReader的环境和属性
       beanDefinitionReader.setEnvironment(getEnvironment());
      // ApplicationContext也继承了ResourceLoader接口
       beanDefinitionReader.setResourceLoader(this);
      // entityResolver在parse时会用到
       beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

       // 初始化beanDefinitionReader,子类可以实现这个方法,做一些个性化配置和初始化
       initBeanDefinitionReader(beanDefinitionReader);

      // 开始load xml文件,这一步开始才是真正读取XML文件了。前面都是做一些环境配置之类的事情
       loadBeanDefinitions(beanDefinitionReader);
    }

loadBeanDefinitions()中先创建beanDefinitionReader,然后配置它的环境,设置成员属性,最后才是真正干活的,也就是读取XML配置文件。我们来看真正读取XML的这一步。

    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
      // 获取XML配置文件的地址,还记得前面讲到过的web.xml中的contextConfigLocation元素吧,它指明了XML配置文件的地址。如果web.xml中没有配置,则读取默认的地址,参看后面分析
       String[] configLocations = getConfigLocations();
       if (configLocations != null) {
         // 遍历读取每个配置文件
          for (String configLocation : configLocations) {
             reader.loadBeanDefinitions(configLocation);
          }
       }
    }

2.3 getConfigLocations()

我们先分析下getConfigLocations方法, 它会获取到spring XML配置文件的地址。

    // 获取配置文件地址,从web.xml中读取。读取不到,则使用默认地址
    protected String[] getConfigLocations() {
            return (this.configLocations != null ? this.configLocations : getDefaultConfigLocations());
    }

    // 获取默认的xml配置文件地址
    public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";
    public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";
    public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";

    protected String[] getDefaultConfigLocations() {
       if (getNamespace() != null) {
         // 设置了容器namespace时,返回/WEB-INF/ + ApplicationContext的namespace + .xml
          return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX};
       }
       else {
         // 没有设置namespace时,直接返回 /WEB-INF/applicationContext.xml
          return new String[] {DEFAULT_CONFIG_LOCATION};
       }
    }

我们先获取XML文件地址,然后再读取XML文件,下面重点分析reader如何读取xml文件的

2.4 XmlBeanDefinitionReader.loadBeanDefinitions()

    // XmlBeanDefinitionReader读取XML文件
    public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
        // 一段log,省略

       // 将Resource对象添加到hashSet中,不是很关键
       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 {
         // 获取Resource对象的输入流
          InputStream inputStream = encodedResource.getResource().getInputStream();
          try {
             // 将inputStream封装到InputSource对象中,并设置编码格式
             InputSource inputSource = new InputSource(inputStream);
             if (encodedResource.getEncoding() != null) {
                inputSource.setEncoding(encodedResource.getEncoding());
             }
             // 加载封装好的inputSource对象,读取XML配置文件。关键步骤,后面分析
             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();
          }
       }
    }

XmlBeanDefinitionReader做了一些成员变量设置后,获取传入的Resource对象的输入流,封装成InputSource后,开始真正解析配置文件。下面来看doLoadBeanDefinitions()如何解析XML文件。

    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
          throws BeanDefinitionStoreException {
       try {
          // 加载并解析XML文件,解析方案为社区通用方法,不是Spring所特有的
          Document doc = doLoadDocument(inputSource, resource);

          return registerBeanDefinitions(doc, resource);
       }
       // 各种异常处理,省略
       catch (BeanDefinitionStoreException ex) {
       }
    }

先利用documentLoader加载XML配置文件,然后注册beans。

2.4.1 doLoadDocument 加载xml文件,将InputSource输入流转换为Document对象

    // 加载XML配置文件
    protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
       // 获取entityResolver,errorHandler, validationMode,namespaceAware,它们都有默认值,也可以由用户来设置
      // entityResolver: 解析器,默认ResourceEntityResolver
      // errorHandler: 解析XML时错误处理,默认SimpleSaxErrorHandler
      // validationMode: xml验证模式,默认VALIDATION_XSD
      // namespaceAware: XML命名空间是否敏感,默认false
       return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
             getValidationModeForResource(resource), isNamespaceAware());
    }

    // DefaultDocumentLoader的loadDocument方法
    public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
                ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
        // 创建DocumentBuilderFactory,对应多个实现类,默认com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl
        DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
        if (logger.isDebugEnabled()) {
            logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
        }
        // 创建DocumentBuilder,通过factory创建
        DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
        // 解析输入流,并返回一个Document对象。解析采用的是通用的DocumentBuilderImpl对象,使用DomParser解析xml文件。解析这一步是通用的,不是Spring特有的方法。比较复杂,不展开了。只要知道通过parse后得到了Document对象就可以了。
        return builder.parse(inputSource);
    }

2.4.2 registerBeanDefinitions 将读取XML后的Document转换为BeanDefinition

    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
       // 反射创建documentReader实例,默认为DefaultBeanDefinitionDocumentReader
       BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
       // 获取容器中当前beans数量,已经注册的BeanDefinition会存储在一个Map中,获取Map的size即可。
       int countBefore = getRegistry().getBeanDefinitionCount();
       // 注册beanDefinition,这是关键所在,后面分析
       documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
       // 返回本次注册的数量
       return getRegistry().getBeanDefinitionCount() - countBefore;
    }

    // 反射创建documentReader,默认为DefaultBeanDefinitionDocumentReader
    private Class<?> documentReaderClass = DefaultBeanDefinitionDocumentReader.class;
    protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
            return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));
        }

registerBeanDefinitions的作用就是将上一步中,输入流转换为的Document对象,转换为BeanDefinition对象。主要工作在documentReader.registerBeanDefinitions()中,下面来分析。

    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
       this.readerContext = readerContext;
       logger.debug("Loading bean definitions");
       // root为<beans />标签
       Element root = doc.getDocumentElement();
       doRegisterBeanDefinitions(root);
    }

    // 采用代理进行解析,代理为BeanDefinitionParserDelegate
    protected void doRegisterBeanDefinitions(Element root) {
             // 创建代理
            BeanDefinitionParserDelegate parent = this.delegate;
            this.delegate = createDelegate(getReaderContext(), root, parent);

            if (this.delegate.isDefaultNamespace(root)) {
                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)) {
                        return;
                    }
                }
            }

             // 解析前的处理,DefaultBeanDefinitionDocumentReader没有实现它,子类可以实现,来扩展功能
            preProcessXml(root);
             // 解析root内的XML标签,如<import> <alias> <bean>等
            parseBeanDefinitions(root, this.delegate);
             // 解析后的处理,同样没有实现它,子类可以实现。
            postProcessXml(root);

            this.delegate = parent;
        }

registerBeanDefinitions() 解析下的XML标签,通过BeanDefinitionParserDelegate代理来进行。具体工作在parseBeanDefinitions()中。这里是本篇文章中比较关键的地方。

    protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
       if (delegate.isDefaultNamespace(root)) {
          // 获取<beans>的子节点
          NodeList nl = root.getChildNodes();
          // 遍历子节点
          for (int i = 0; i < nl.getLength(); i++) {
             Node node = nl.item(i);
             if (node instanceof Element) {
                // 子节点是Element对象,默认的子节点,如<import>都是Element对象
                Element ele = (Element) node;
                if (delegate.isDefaultNamespace(ele)) {
                   // 在默认的命名空间url中的元素,是默认定义好的节点,采用parseDefaultElement方法解析
                   parseDefaultElement(ele, delegate);
                }
                else {
                   // 用户自定义的命名空间url中的元素,采用parseCustomElement方法解析
                   delegate.parseCustomElement(ele);
                }
             }
          }
       }
       else {
          // 子节点不是标准的Element元素,比如用户自定义的,采用parseCustomElement方法解析
          delegate.parseCustomElement(root);
       }
    }

parseBeanDefinitions()方法会循环遍历的子节点。如果是默认命名空间内的Element,则采用parseDefaultElement()方法解析,否则采用parseCustomElement()方法。DefaultElement包括、、、嵌套的,其余都为CustomElement,如。

2.4.2.1 parseDefaultElement() 解析DefaultElement

    public static final String IMPORT_ELEMENT = "import";
    public static final String ALIAS_ATTRIBUTE = "alias";
    public static final String BEAN_ELEMENT = "bean";
    public static final String NESTED_BEANS_ELEMENT = "beans";

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

下面我们重点分析下processBeanDefinition(),因为这个和spring息息相关。这个过程十分复杂,所以我们不进行很细致的分析,抓住主要流程就OK了。也不建议非要去了解每行代码做了什么事情,避免过度陷入其中,而忽略了主流程。

    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
       // 解析Element为BeanDefinition,这是重点,后面详细分析
       BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
       if (bdHolder != null) {
          bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
          try {
             // 将BeanDefinition注册到BeanDefinitionMap中,key为beanName
             BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
          }
          catch (BeanDefinitionStoreException ex) {
             getReaderContext().error("Failed to register bean definition with name '" +
                   bdHolder.getBeanName() + "'", ele, ex);
          }
          // 发送注册的消息,相应的监听器就会收到并处理消息了
          getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
       }
    }
    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
       // 获取bean的id属性
       String id = ele.getAttribute(ID_ATTRIBUTE);
       // 获取bean的name属性
       String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

       // 解析name属性,支持多个name
       List<String> aliases = new ArrayList<>();
       if (StringUtils.hasLength(nameAttr)) {
          String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
          aliases.addAll(Arrays.asList(nameArr));
       }

       // id属性赋值到beanName变量中,注意不是name属性。如果没有id属性,则使用name属性的第一个值
       String beanName = id;
       if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
          beanName = aliases.remove(0);
       }

       // 校验beanname的唯一性,这也是为啥id属性值必须唯一的原因
       if (containingBean == null) {
          checkNameUniqueness(beanName, aliases, ele);
       }

       // 解析bean节点为GenericBeanDefinition,后面详细分析
       AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
       // 后面不是很重要了
       if (beanDefinition != null) {
          if (!StringUtils.hasText(beanName)) {
             try {
                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);
                   }
                }

             }
             catch (Exception ex) {
                error(ex.getMessage(), ele);
                return null;
             }
          }
          String[] aliasesArray = StringUtils.toStringArray(aliases);
          return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
       }

       return null;
    }
    public static final String PARENT_ATTRIBUTE = "parent";
    public static final String CLASS_ATTRIBUTE = "class";

    public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean) {
        this.parseState.push(new BeanEntry(beanName));
        // 获取class和parent属性
        String className = null;
        if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
            className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
        }
        String parent = null;
        if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
            parent = ele.getAttribute(PARENT_ATTRIBUTE);
        }

        try {
             // 反射实例化bean为GenericBeanDefinition
            AbstractBeanDefinition bd = createBeanDefinition(className, parent);
            // 解析节点中其他属性,如scope, singleton等。后面详细分析
            parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
            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;
        }
         // 各种异常处理
        catch (ClassNotFoundException ex) {
            error("Bean class [" + className + "] not found", ele, ex);
        }
        ...
        return null;
    }
    // 反射实例化,创建GenericBeanDefinition对象
    public static AbstractBeanDefinition createBeanDefinition(
          @Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {

       GenericBeanDefinition bd = new GenericBeanDefinition();
       bd.setParentName(parentName);
       if (className != null) {
          if (classLoader != null) {
             bd.setBeanClass(ClassUtils.forName(className, classLoader));
          }
          else {
             bd.setBeanClassName(className);
          }
       }
       return bd;
    }
    // 解析<bean>中的各种属性,比如scope,lazy-init等
    public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
          @Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {

       // 解析singleton
       if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
          error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
       }
       // 解析scope
       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
       if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
          bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
       }
       // 解析lazy-init
       String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
       if (DEFAULT_VALUE.equals(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
       String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
       if ("".equals(autowireCandidate) || DEFAULT_VALUE.equals(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
       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);
          if (!"".equals(initMethodName)) {
             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;
    }

2.4.2.2 parseCustomElement() 解析CustomElement

    public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
       String namespaceUri = getNamespaceURI(ele);
       if (namespaceUri == null) {
          return null;
       }
       // 根据命名空间url获取具体的NamespaceHandler,比如<context:component-scan>对应的就是用户自定义的ContextNamespaceHandler。
       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来解析用户自定义的CustomElement
       return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
    }

parseCustomElement()首先根据自定义标签的命名空间,生成具体的NamespaceHandler。一般要由用户自己定义。然后调用parse方法进行解析,这个也是用户自定义的。这里就不展开分析了。

3 流程图

20191017100224\_1.png


来源:[]()

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » Spring源码分析3 — spring XML配置文件的解析流程

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏