美文网首页
Spring refresh函数(1)——Spring的Bean

Spring refresh函数(1)——Spring的Bean

作者: 雁阵惊寒_zhn | 来源:发表于2022-01-12 21:36 被阅读0次

    后续的Spring内容在我的公众号《魔法师和ta的南瓜小屋》或简书其他文章详细介绍。

    Spring中最重要的函数实现refresh()函数,Spring中两项核心——控制反转(IoC)和面向切面编程(AOP)——就是在这里实现完成的。BeanFactory和BeanDefinition在Spring和Spring Boot中作用是完全相同的。下面源代码选自Spring 5.2.2.RELEASE版本,以Spring xml文件配置Bean为示例(Spring Boot依赖注解)。由于目前Spring Boot已经逐渐取代原来基于xml配置的Spring,渐渐成为各大互联网或软件公司的主力框架。为了贴合实际应用,会插入Spring Boot区别的地方。

    BeanFactory

    BeanFactory顾名思义就是“生成Bean的工厂”,Spring通过BeanFactory对Bean进行创建。
    refresh()函数中调用obtainFreshBeanFactory()获取BeanFactory实例。

    // Tell the subclass to refresh the internal bean factory.
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        refreshBeanFactory();
        return getBeanFactory();
    }
    

    抽象类AbstractRefreshableApplicationContext具体实现refreshBeanFactory()函数,默认的BeanFactory对象为DefaultListableBeanFactory类。

    //Spring
    @Override
    protected final void refreshBeanFactory() throws BeansException {
        if (hasBeanFactory()) {
          destroyBeans();
          closeBeanFactory();
        }
        try {
          DefaultListableBeanFactory beanFactory = createBeanFactory();
          beanFactory.setSerializationId(getId());
          customizeBeanFactory(beanFactory);
          loadBeanDefinitions(beanFactory);
          synchronized (this.beanFactoryMonitor) {
            this.beanFactory = beanFactory;
          }
        }
        catch (IOException ex) {
          throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }
    

    而在Spring Boot中虽然也经过了函数obtainFreshBeanFactory(),但是调用的是类GenericApplicationContext refreshBeanFactory()函数。此时BeanFactory对象实际已经创建完成,仅仅设置SerializationId。BeanFactory对象的创建在GenericApplicationContext的无参数构造函数中。

    //Spring Boot
    @Override
    protected final void refreshBeanFactory() throws IllegalStateException {
        if (!this.refreshed.compareAndSet(false, true)) {
          throw new IllegalStateException(
              "GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
        }
        this.beanFactory.setSerializationId(getId());
    }
    

    这是Spring Boot相较于Spring的一个改动,Spring Boot将BeanFactory对象的创建提前到了上下文创建时。相同的是默认的BeanFactory对象都是DefaultListableBeanFactory类。


    图片选自我的公众号

    BeanDefinition

    BeanDefinition是“Bean在Spring中的描述”。Spring解析配置文件、注解等获取需要注入的Bean信息,使用BeanDefinition结构存储这些Bean的信息,包括Bean的名字,是否是单例,属性值,构造方法等等。之后从这些BeanDefinition获取需要的信息对Bean进行实例化。

    Spring在函数obtainFreshBeanFactory()中完成xml配置信息向BeanDefinition转化。

    调用AbstractApplicationContext类中的函数obtainFreshBeanFactory()。

    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        refreshBeanFactory();
        return getBeanFactory();
    }
    

    类AbstractRefreshableApplicationContext中的refreshBeanFactory()函数。

    @Override
    protected final void refreshBeanFactory() throws BeansException {
        if (hasBeanFactory()) {
          destroyBeans();
          closeBeanFactory();
        }
        try {
          DefaultListableBeanFactory beanFactory = createBeanFactory();
          beanFactory.setSerializationId(getId());
          customizeBeanFactory(beanFactory);
          loadBeanDefinitions(beanFactory);
          synchronized (this.beanFactoryMonitor) {
            this.beanFactory = beanFactory;
          }
        }
        catch (IOException ex) {
          throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }
    

    从loadBeanDefinitions()函数开始,按照如下路径找到类XmlBeanDefinitionReader中的函数doLoadBeanDefinitions()。

    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;
        }
        catch (BeanDefinitionStoreException ex) {
          throw ex;
        }
        catch (SAXParseException ex) {
          throw new XmlBeanDefinitionStoreException(resource.getDescription(),
              "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
        }
        catch (SAXException ex) {
          throw new XmlBeanDefinitionStoreException(resource.getDescription(),
              "XML document from " + resource + " is invalid", ex);
        }
        catch (ParserConfigurationException ex) {
          throw new BeanDefinitionStoreException(resource.getDescription(),
              "Parser configuration exception parsing XML from " + resource, ex);
        }
        catch (IOException ex) {
          throw new BeanDefinitionStoreException(resource.getDescription(),
              "IOException parsing XML document from " + resource, ex);
        }
        catch (Throwable ex) {
          throw new BeanDefinitionStoreException(resource.getDescription(),
              "Unexpected exception parsing XML document from " + resource, ex);
        }
    }
    

    获取Document实例,注册BeanDefinition信息。

    Document doc = doLoadDocument(inputSource, resource);
    int count = registerBeanDefinitions(doc, resource);
    

    走到类XmlBeanDefinitionReader中的函数registerBeanDefinitions()。

    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        int countBefore = getRegistry().getBeanDefinitionCount();
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        return getRegistry().getBeanDefinitionCount() - countBefore;
    }
    

    然后类DefaultBeanDefinitionDocumentReader中的registerBeanDefinitions()。

    @Override
    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
        this.readerContext = readerContext;
        doRegisterBeanDefinitions(doc.getDocumentElement());
    }
    

    类DefaultBeanDefinitionDocumentReader中的doRegisterBeanDefinitions()。创建delegate对象是用于解析xml文件中Bean的定义,parseBeanDefinitions()函数具体执行xml配置到BeanDefinition结构的转换。

    protected void doRegisterBeanDefinitions(Element root) {
        // Any nested <beans> elements will cause recursion in this method. In
        // order to propagate and preserve <beans> default-* attributes correctly,
        // keep track of the current (parent) delegate, which may be null. Create
        // the new (child) delegate with a reference to the parent for fallback purposes,
        // then ultimately reset this.delegate back to its original (parent) reference.
        // this behavior emulates a stack of delegates without actually necessitating one.
        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);
            // We cannot use Profiles.of(...) since profile expressions are not supported
            // in XML config. See SPR-12458 for details.
            if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
              if (logger.isDebugEnabled()) {
                logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                    "] not matching: " + getReaderContext().getResource());
              }
              return;
            }
          }
        }
    
        preProcessXml(root);
        parseBeanDefinitions(root, this.delegate);
        postProcessXml(root);
    
        this.delegate = parent;
    }
    

    类DefaultBeanDefinitionDocumentReader中函数parseBeanDefinitions(),由于是默认标签,之后调用parseDefaultElement()方法。自定义标签则调用delegate.parseCustomElement()。

    在parseDefaultElement()方法中依据标签的不同注册为对应的BeanDefinition结构。

    private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
        if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
          importBeanDefinitionResource(ele);
        }
        else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
          processAliasRegistration(ele);
        }
        else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
          processBeanDefinition(ele, delegate);
        }
        else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
          // recurse
          doRegisterBeanDefinitions(ele);
        }
    }
    

    Spring Boot中,BeanDefinition的注册是在函数invokeBeanFactoryPostProcessors()中完成的。公众号中其他文章会详细介绍Spring Boot的invokeBeanFactoryPostProcessors()函数以及Spring Boot。

    //Spring Boot
    //Invoke factory processors registered as beans in the context.
    invokeBeanFactoryPostProcessors(beanFactory);
    

    相关文章

      网友评论

          本文标题:Spring refresh函数(1)——Spring的Bean

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