Spring source code analysis - The IOC container load

In this paper an article SpringIOC source connected to the control treatment before reversal (https://mp.weixin.qq.com/s/9RbVP2ZQVx9-vKngqndW1w) continue with the analysis

First posted core 11 steps to refresh the Spring bean container are to worship (be sure to let me learn ... Amen)

// 完成IoC容器的创建及初始化工作
@Override
public void refresh() throws BeansException, IllegalStateException {
  synchronized (this.startupShutdownMonitor) {

    // 1: 刷新前的准备工作。
    prepareRefresh();

    // 告诉子类刷新内部bean 工厂。
    //  2:创建IoC容器(DefaultListableBeanFactory),加载解析XML文件(最终存储到Document对象中)
    // 读取Document对象,并完成BeanDefinition的加载和注册工作
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

    //  3: 对IoC容器进行一些预处理(设置一些公共属性)
    prepareBeanFactory(beanFactory);

    try {

      //  4:  允许在上下文子类中对bean工厂进行后处理。
      postProcessBeanFactory(beanFactory);

      //  5: 调用BeanFactoryPostProcessor后置处理器对BeanDefinition处理
      invokeBeanFactoryPostProcessors(beanFactory);

      //  6: 注册BeanPostProcessor后置处理器
      registerBeanPostProcessors(beanFactory);

      //  7: 初始化一些消息源(比如处理国际化的i18n等消息源)
      initMessageSource();

      //  8: 初始化应用事件多播器
      initApplicationEventMulticaster();

      //  9: 初始化一些特殊的bean
      onRefresh();

      //  10: 注册一些监听器
      registerListeners();

      //  11: 实例化剩余的单例bean(非懒加载方式)
      //      注意事项:Bean的IoC、DI和AOP都是发生在此步骤
      finishBeanFactoryInitialization(beanFactory);

      //  12: 完成刷新时,需要发布对应的事件
      finishRefresh();
    }

    catch (BeansException ex) {
      if (logger.isWarnEnabled()) {
        logger.warn("Exception encountered during context initialization - " +
                    "cancelling refresh attempt: " + ex);
      }

      // 销毁已经创建的单例避免占用资源
      destroyBeans();

      // 重置'active' 标签。
      cancelRefresh(ex);

      // 传播异常给调用者
      throw ex;
    }

    finally {

      // 重置Spring核心中的常见内省缓存,因为我们可能不再需要单例bean的元数据了...
      resetCommonCaches();
    }
  }
}

The following analyzes the process in the above-described second step: creating and parsing IOC container

We entered the analysis, first of all calls to AbstractApplicationContextthe obtainFreshBeanFactorymethod that will be refreshed IOC container and remove the BeanFactory, the following code

// 告诉内部子类刷新内部的bean factory
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        // 主要是通过该方法完成IoC容器的刷新
        // ClassPathXmlApplicationContext.refreshBeanFactory 调用的是 AbstractRefreshApplicationContext
        // AnnotationConfigApplicationContext.refreshBeanFactory调用的是GenericApplicationContext
        refreshBeanFactory();
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    ...
        return beanFactory;
    }
  1. The first step, refreshBeanFactoryrefresh Bean factory, refreshBeanFactory is an interface that is defined in AbstractApplicationContext in, look at the definition of the interface JavaDoc
/**
     * 子类必须实现这个方法才能执行实际的配置加载。此方法在任何其他初始化工作开始之前由refresh()方法调用
     * 一个子类创建了一个新的 bean factory 并且持有对它的引用,或者返回它拥有的单个BeanFactory实例。
     * 在后一种情况下,如果多次刷新上下文,它通常会抛出 IllegalStateException。
     */
    protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;

It has two implementation classes, the default AbstractRefreshableApplicationContextclass, it follows refreshBeanFactory

@Override
protected final void refreshBeanFactory() throws BeansException {
  // 如果之前有IoC容器,则销毁
  if (hasBeanFactory()) {
    destroyBeans();
    closeBeanFactory();
  }
  try {
    // 创建IoC容器,也就是 DefaultListableBeanFactory, 初始化AbstractBeanFactory
    // 注册BeanNameAware,BeanClassLoaderAware,BeanFactoryAware, 设置当前BeanFactory
    DefaultListableBeanFactory beanFactory = createBeanFactory();
    beanFactory.setSerializationId(getId());
    // 设置工厂的属性:是否允许BeanDefinition覆盖和是否允许循环依赖
    customizeBeanFactory(beanFactory);
    // 调用载入BeanDefinition的方法,在当前类中只定义了抽象的loadBeanDefinitions方法,具体的实现调用子类容器
    loadBeanDefinitions(beanFactory);
    synchronized (this.beanFactoryMonitor) {
      this.beanFactory = beanFactory;
    }
  }
  catch (IOException ex) {
    throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
  }
}

If there IOC container before, then it is destruction, and closed containers. On the second occasion calls ClassPathXmlApplicationContext ( "Profile"), because it is the first to load the configuration file, not yet created BeanFactory, so hasBeanFactory () returns false.

This step is to create the following IOC container, that is,DefaultListableBeanFactory

// 为上下文创建一个内部工厂,默认的实现创建了一个内部的DefaultListableBeanFactory.getInternalParentBeanFactory(),
// 在子类中被重写,例如自定义DefaultListableBeanFactory的设置。
protected DefaultListableBeanFactory createBeanFactory() {
  return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}

Transfer of the above method is a getInternalParentBeanFactory()method, we first look at this method:

protected BeanFactory getInternalParentBeanFactory() {
  return (getParent() instanceof ConfigurableApplicationContext) ?
    ((ConfigurableApplicationContext) getParent()).getBeanFactory() : getParent();
}

getParent () This method returns the parent context, if there is no (parent), then return null (it indicates that the context is inherited root of the tree.) meaning of this code is to say if it implements ConfigurableApplicationContextReturns parent context BeanFactory, if not, then return to the parent context itself. Because no context is provided through the parent node, so in this case the getInternalParentBeanFactory () method returns null.

Next to return a DefaultListableBeanFactoryfirst look at the inheritance hierarchy of DefaultListableBeanFactory

It calls the process is as follows:

  • In AbstractRefreshableApplicationContextreturning a class DefaultListableBeanFactory constructor
  • DefaultListableBeanFactoryConstructor calls AbstractAutowireCapableBeanFactory constructor
  • AbstractAutowireCapableBeanFactoryThe constructor arguments invoked AbstractAutowireCapableBeanFactory no-argument constructor, and registered BeanNameAware, BeanFactoryAware, BeanClassLoaderAware interface. And provided setParentBeanFactory (parentBeanFactory) is null (parentBeanFactory is above getInternalParentBeanFactory () method returns the value);

  • AbstractAutowireCapableBeanFactoryWe will call the parent class AbstractBeanFactory constructor with no arguments and initializes.

At this time will bring a series of initialization DefaultListableBeanFactory field. Bean said the factory is DefaultListableBeanFactory

  1. In createBeanFactory () after setting Globally Unique Id give ClassPathXmlApplicationContext
beanFactory.setSerializationId(getId());
  1. The third step is to set DefaultListableBeanFactoryattributes, whether to allow overwriting Bean definition information and whether to allow the circular dependency. Is not set, the default is null
/*
* 通过上下文自定义内部bean工厂。 尝试调用每一个refresh 方法。
     * 默认实现应用此上下文setAllowBeanDefinitionOverriding 是否允许Bean定义重写
     * 和 setAllowCircularReferences 是否允许循环依赖设置。
     * 如果特殊情况,可以在子类中重写以任何自定义DefaultListableBeanFactory 设置。
*/
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
        if (this.allowBeanDefinitionOverriding != null) {
            beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
        }
        if (this.allowCircularReferences != null) {
            beanFactory.setAllowCircularReferences(this.allowCircularReferences);
        }
    }
  1. The most critical step, load the Bean definition information. All about Bean Definitions will be resolved in this step of the method. BeanDefinition loading method call in the current class only defines the abstract loadBeanDefinitionsmethods, a specific implementation calls subclass container AbstractXmlApplicationContextin loadBeanDefinitions method, specific code as follows
// 通过XmlBeanDefinitionReader 加载bean 定义信息。
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
  // 创建一个BeanDefinition阅读器,通过阅读XML文件,真正完成BeanDefinition的加载和注册
  XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

  // 配置bean 定义阅读器和上下文资源加载环境。
  beanDefinitionReader.setEnvironment(this.getEnvironment());
  beanDefinitionReader.setResourceLoader(this);
  beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

  // 允许子类提供自定义初始化的reader,然后继续加载bean定义信息。
  initBeanDefinitionReader(beanDefinitionReader);

  // 委托给BeanDefinition阅读器去加载BeanDefinition
  loadBeanDefinitions(beanDefinitionReader);
}
  • First look at the first step, create XmlBeanDefinitionReader and BeanDefinition loading and registration. Initialization XmlBeanDefinitionReader (beanFactory) constructor, then call AbstractBeanDefinitionReader (BeanDefinitionRegistry registry) constructor, because DefaultListableBeanFactoryto achieve the BeanDefinitionRegistry interfaces, so put DefaultListableBeanFactory as a BeanDefinitionRegistry pass inside. Let's look at the code
/* 通过bean 工厂创建一个新的 AbstractBeanDefinitionReader。
     如果传入的bean 工厂不仅实现了BeanDefinitionRegistry 接口还实现了ResourceLoader 接口。
   将会使用默认的ResourceLoader。 这是 ApplicationContext 实现的情况。
   如果给定一个普通的BeanDefinitionRegistry,则默认的 ResourceLoader 会是PathMatchingResourcePatternResolver
   如果传入的bean 工厂实现了 EnvironmentCapable,则此读取器将使用此环境。否则,这个读取器
   将会初始化并且使用 StandardEnvironment。 所有ApplicationContext的实现都是 EnvironmentCapable,
     然而通常BeanFactory 的实现则不是。
 */
protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
  ...
  if (this.registry instanceof ResourceLoader) {
    this.resourceLoader = (ResourceLoader) this.registry;
  }
  else {
    this.resourceLoader = new PathMatchingResourcePatternResolver();
  }
  if (this.registry instanceof EnvironmentCapable) {
    this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
  }
  else {
    this.environment = new StandardEnvironment();
  }
}

The above code means that, if BeanDefinitionRegistryrealized ResourceLoader interfaces , will be cast to ResourceLoader, otherwise, will be a new PathMatchingResourcePatternResolver () , if realized EnvironmentCapable interfaces , direct access to the system environment, or to direct a new StandardEnvironment .

  • After completing the first step, and then configure the bean reader and context resource loading environment that allows subclasses to provide custom initialization of the reader, and then continue to load the bean definition information. This step is hope that subclasses implement custom bean loading information .
  • The final step be taken in the true sense of bean loading entrusted to BeanDefinition reader to load BeanDefinition, look at the specific resolution process
// 委托给XmlBeanDefinition阅读器去加载BeanDefinition
 // loadBeanDefinitions(beanDefinitionReader);  ↓
    
  @Override
    public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
        // 将读入的XML资源进行特殊编码处理
        return loadBeanDefinitions(new EncodedResource(resource));
    }

  // loadBeanDefinitions  ↓

    // loadBeanDefinitions(resources) 经过一系列的调用最终会调用到下面的代码
  // XmlBeanDefinitionReader 部分代码省略
    public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
        ...
    // 从InputStream中得到XML的解析源
    InputSource inputSource = new InputSource(inputStream);
    if (encodedResource.getEncoding() != null) {
       inputSource.setEncoding(encodedResource.getEncoding());
    }
    // 这里是具体的读取过程
    return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
    }
  
  // doLoadBeanDefinitions ↓
  protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
            throws BeanDefinitionStoreException {
    
            // 通过DOM4J加载解析XML文件,最终形成Document对象
            Document doc = doLoadDocument(inputSource, resource);
        // 通过对Document对象的操作,完成BeanDefinition的加载和注册工作
        return registerBeanDefinitions(doc, resource);
    }
  
  // registerBeanDefinitions  ↓
  public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        // 创建BeanDefinitionDocumentReader来解析Document对象,完成BeanDefinition解析
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        // 获得容器中已经注册的BeanDefinition数量
        int countBefore = getRegistry().getBeanDefinitionCount();
        // 解析过程入口,BeanDefinitionDocumentReader只是个接口,具体的实现过程在DefaultBeanDefinitionDocumentReader完成
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        // 统计新的的BeanDefinition数量
        return getRegistry().getBeanDefinitionCount() - countBefore;
    }

At this point still just created needs to resolve the viewer object, the object document analysis, parsing the preparatory work before,

Here to talk about BeanDefinitionDocumentReaderthis interface:

/*
 * 每个要解析的文档实例化:实现可以在执行
 * registerBeanDefinitions 方法时保存实例变量中的状态
 * 例如,为文档中的所有bean定义定义的全局设置。
*/
public interface BeanDefinitionDocumentReader {
  /*
  * 从 DOM 文档中读取Bean 定义信息并且通过阅读器上下文环境把它们注册进registry中
  */
  void registerBeanDefinitions(Document doc, XmlReaderContext readerContext)
            throws BeanDefinitionStoreException;
}

The default implementation class is only one that DefaultBeanDefinitionDocumentReader, such responsible for doing the real work to resolve bean.

The following registerBeanDefinitionsmethod will be completed after the real bean analytical work:

DefaultBeanDefinitionDocumentReader.java

// 这个实现用来解析 spring-beans 约束
// 打开DOM 文档,初始化默认<beans/>的设置;然后解析其中的bean定义信息。
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
  this.readerContext = readerContext;
  logger.debug("Loading bean definitions");
  // 获得Document的根元素<beans>标签
  Element root = doc.getDocumentElement();
  // 真正实现BeanDefinition解析和注册工作
  doRegisterBeanDefinitions(root);
}

//      doRegisterBeanDefinitions(root);  ↓
protected void doRegisterBeanDefinitions(Element root) {

        /*
            任何嵌套的<beans>元素都将导致此方法中的递归。 为了正确传播和保留<beans>default-* 属性,跟踪当前的
            父委托,可能为null。
            创建新的(子)委托,引用父项以进行回退,然后最终将this.delegate重置为其原始(父)引用。 此行为模拟了一堆代理,而实际上并不需要一个代理。
         */

        // 这里使用了委托模式,将具体的BeanDefinition解析工作交给了BeanDefinitionParserDelegate去完成
        BeanDefinitionParserDelegate parent = this.delegate;
        this.delegate = createDelegate(getReaderContext(), root, parent);

        // 判断该根标签是否包含http://www.springframework.org/schema/beans默认命名空间
        ...
      
      
        // 在解析Bean定义之前,进行自定义的解析,增强解析过程的可扩展性
        preProcessXml(root);
        // 委托给BeanDefinitionParserDelegate,从Document的根元素开始进行BeanDefinition的解析
        parseBeanDefinitions(root, this.delegate);
        // 在解析Bean定义之后,进行自定义的解析,增加解析过程的可扩展性
        postProcessXml(root);

        this.delegate = parent;
    }

See here has really not easy, you need a break? How should I say, this thing is the need to source durability patience and you need to invest a lot of energy, read it again not remember too normal, and look at the source code on the premise that no one bothered requires an extremely quiet environment.

tips: wear headphones will be much better

Before returning to the topic, let me ask you a question, you know the difference between a proxy mode and a mode of commission do?

I understand it this way

Delegate pattern of their own do not do this thing does, but to do things to others
agency model is to make people a hand, while he is the real protagonist do this thing, because the proxy implementation class (implements InvocationHandler class) just Dazui gun person.

Back to the topic, do analytical work in real time, will create a first class delegate BeanDefinitionParserDelegate, then the first to know about the class.

// 用于解析XML bean定义的有状态委托类。 旨在供主解析器和任何扩展使用
public class BeanDefinitionParserDelegate {
  
  // 此方法也就是委托给 BeanDefinitionParserDelegate 去做的事情
  protected BeanDefinitionParserDelegate createDelegate(
            XmlReaderContext readerContext, Element root, @Nullable BeanDefinitionParserDelegate parentDelegate) {

        BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
        delegate.initDefaults(root, parentDelegate);
        return delegate;
    }
}

It is mainly done things in the initDefaultsprocess, along with a look at this method

/*
     * 初始化默认的 懒加载,自动注入,依赖检查设置, 初始化方法,销毁方法和合并设置。
     * 如果未在本地显式设置默认值,则通过回退到给定父级来支持嵌套的“beans”元素用例。
     */
public void initDefaults(Element root, @Nullable BeanDefinitionParserDelegate parent) {
  populateDefaults(this.defaults, (parent != null ? parent.defaults : null), root);
  this.readerContext.fireDefaultsRegistered(this.defaults);
}
/**
     * in case the defaults are not explicitly set locally.
     * 使用默认的 lazy-init,autowire,依赖检查设置,init-method,destroy-method 和 合并设置 属性 填充给定的
     * DocumentDefaultsDefinition,如果未在本地显式设置默认值,则支持嵌套的'beans'元素用例,返回parentDefaults
     */
    protected void populateDefaults(DocumentDefaultsDefinition defaults, @Nullable DocumentDefaultsDefinition parentDefaults, Element root) {
        // default-lazy-init
        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);

    // 余下的代码和lazyinit 的逻辑相同,也是解析方法注释中的各种属性。 这里碍于篇幅原因暂不贴出了
        ...
    //   
      
        defaults.setSource(this.readerContext.extractSource(root));
    }

The method then returns to the entrance has been created that is commissioned BeanDefinitionParserDelegate parent = this.delegate;, then it is left to the developer of two Spring interfaces for developers to implement their own

...
// 在解析Bean定义之前,进行自定义的解析,增强解析过程的可扩展性
preProcessXml(root);
// 委托给 BeanDefinitionParserDelegate,从Document的根元素开始进行BeanDefinition的解析
parseBeanDefinitions(root, this.delegate);
// 在解析Bean定义之后,进行自定义的解析,增加解析过程的可扩展性
postProcessXml(root);

Let us look at parseBeanDefinitions(root, this.delegate);this method is to just create a BeanDefinitionParserDelegatecommission to resolve specific labels such as lazy-init attribute

/**
     * 解析文档对象的根目录节点: import, alias, bean
     */
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
  // 加载的Document对象是否使用了Spring默认的XML命名空间(beans命名空间)
  if (delegate.isDefaultNamespace(root)) {
    // 获取Document对象根元素的所有子节点(bean标签、import标签、alias标签和其他自定义标签context、aop等)
    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;
        // bean标签、import标签、alias标签,则使用默认解析规则
        if (delegate.isDefaultNamespace(ele)) {
          parseDefaultElement(ele, delegate);
        }
        else {//像context标签、aop标签、tx标签,则使用用户自定义的解析规则解析元素节点
          delegate.parseCustomElement(ele);
        }
      }
    }
  }
  else {
    // 如果不是默认的命名空间,则使用用户自定义的解析规则解析元素节点
    delegate.parseCustomElement(root);
  }
}

The above steps can be divided into three steps:

  • First determine whether the delegate class using Spring default XML namespace (beans namespace), to determine if the node is taken out of the bean, import, alias , then use the default parsing rules
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);
  }
  // 解析内置<bean>标签
  else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
    // recurse
    // 递归调用
    doRegisterBeanDefinitions(ele);
  }
}
  • If the judgment is not taken out of the default node, the default custom parsing rules will be used, context tag, label AOP, tx tags will be used by default this analytical method
@Nullable
public BeanDefinition parseCustomElement(Element ele) {
  // 解析自定义标签
  return parseCustomElement(ele, null);
}

@Nullable
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
  // 获取命名空间URI(就是获取beans标签的xmlns:aop或者xmlns:context属性的值)
  String namespaceUri = getNamespaceURI(ele);
  if (namespaceUri == null) {
    return null;
  }
  // 根据不同的命名空间URI,去匹配不同的NamespaceHandler(一个命名空间对应一个NamespaceHandler)
  // 此处会调用DefaultNamespaceHandlerResolver类的resolve方法
  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的解析方法
  return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
  • If not using beans namespace will use self-defined analytical method to parse

The method then parsed far back as the AbstractApplicationContextrefresh bean Factory method

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
  // 主要是通过该方法完成IoC容器的刷新
  // ClassPathXmlApplicationContext.refreshBeanFactory 调用的是 AbstractRefreshApplicationContext
  // AnnotationConfigApplicationContext.refreshBeanFactory调用的是GenericApplicationContext
  refreshBeanFactory();
  ConfigurableListableBeanFactory beanFactory = getBeanFactory();
  if (logger.isDebugEnabled()) {
    logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
  }
  return beanFactory;
}

Bean object thus taken out can be used.

The next article to resolve what The third step: The IoC container some preprocessing

Guess you like

Origin www.cnblogs.com/cxuanBlog/p/11514796.html