spring source code refresh Part 2

Posted by Crimpage on Mon, 10 Jan 2022 06:20:02 +0100

spring source code refresh Part 2

Hello, I'm a classmate of programmer Tian

The previous article gave an overall interpretation of the spring core startup method refresh, but only in general. Next, a systematic article will be published to deeply interpret the source code of each method.

For the first article, see Method overview of spring source code

First, the first method is the prepareRefresh() method, which is very simple and is not the focus of this article. This method records the start time of the container and initializes the listening container.

protected void prepareRefresh() {
        // Switch to active
        //Record start time
        this.startupDate = System.currentTimeMillis();
        System.out.println("spring Start time is--------------------" + this.startupDate);
        this.closed.set(false);
        System.out.println("spring Mark as not closed--------------------" + this.closed);
        this.active.set(true);
        System.out.println("spring Current active state--------------------" + this.active);
 
        if (logger.isDebugEnabled()) {
            if (logger.isTraceEnabled()) {
                logger.trace("Refreshing " + this);
            } else {
                logger.debug("Refreshing " + getDisplayName());
            }
        }
        // Initialize any placeholder property sources in the context environment.
        //Empty method
        initPropertySources();
 
        // Validate that all properties marked as required are resolvable:
        // see ConfigurablePropertyResolver#setRequiredProperties
        //Validate xml configuration file
        getEnvironment().validateRequiredProperties();
 
        // Store pre-refresh ApplicationListeners...
        //Initialize the applicationlisters listening container
        if (this.earlyApplicationListeners == null) {
            this.earlyApplicationListeners = new LinkedHashSet<>              (this.applicationListeners);
        } else {
            // Reset local application listeners to pre-refresh state.
            this.applicationListeners.clear();
            this.applicationListeners.addAll(this.earlyApplicationListeners);
        }
 
        // Allow for the collection of early ApplicationEvents,
        // to be published once the multicaster is available...
        this.earlyApplicationEvents = new LinkedHashSet<>();
    }

Readers can take a general look at this method and quickly grasp it as a whole.

The next is today's highlight - the obtainFreshBeanFactory() method, which is the second method in the refresh() method and one of the core methods in the whole refresh() method.

The main function of this method is to initialize BeanFactory, load beans, register beans, etc. (Bean did not complete initialization)

Click in the obtainFreshBeanFactory() method to find out.

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
   // Close the old BeanFactory (if any), create a new BeanFactory, load Bean definitions, register beans, and so on
   refreshBeanFactory();
​
   // Return to the BeanFactory you just created
   ConfigurableListableBeanFactory beanFactory = getBeanFactory();
   if (logger.isDebugEnabled()) {
      logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
   }
   return beanFactory;
}

refreshBeanFactory() should be the highlight of this method. Let's go deeper.

@Override
protected final void refreshBeanFactory() throws BeansException {
   // If BeanFactory has been loaded in ApplicationContext, destroy all beans and close BeanFactory
   // Note that there can be more than one BeanFactory in an application. This does not mean whether there is a BeanFactory in the global application, but whether there is a BeanFactory in the current ApplicationContext
   if (hasBeanFactory()) {
      destroyBeans();
      closeBeanFactory();
   }
   try {
      // Initialize a DefaultListableBeanFactory. Why use this BeanFactory? Because this is the best BeanFactory.
      DefaultListableBeanFactory beanFactory = createBeanFactory();
      // Serialization for BeanFactory
      beanFactory.setSerializationId(getId());
​
      // Set two configuration properties of BeanFactory: whether to allow Bean overwrite and whether to allow circular reference
      customizeBeanFactory(beanFactory);
​
      // Load beans into 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);
   }
}

Simply put, why is DefaultListableBeanFactory the best BeanFactory? You can see the inheritance diagram.

  // Set two configuration properties of BeanFactory: whether to allow Bean overwrite and whether to allow circular reference
  customizeBeanFactory(beanFactory);

This method is just a setting to set whether circular dependency is allowed. What is circular dependency? That is, they are interdependent between A-B-C. spring has its own mechanism to deal with circular dependency. For analysis in future articles, this step is only to configure whether circular dependency is allowed. Readers can know it clearly.

   // This method will load each Bean according to the configuration, and then put it into the BeanFactory
  loadBeanDefinitions(beanFactory);

After the above series of steps, a beandefinition is formed. Beandefinition is what we often call a bean, that is, an enhanced version of an object.

Next, you need to add the bean to the beanfactory. This step is left to the loadBeanDefinitions() method.

spring method naming is really exquisite. Just look at the method name and probably know what each method does!

Create a bean definition reader (bean reader) to read beans in xml. Although xml is rarely used, it is classic to use it as an example.

The real work is loadbean definitions (bean definition reader). It's a long way down. Parse the bean in our xml into BeanDefinition, and call the registerBeanDefinition() method to register it in the registry and send registration events.

To sum up, the Bean container has been initialized here, and the < Bean / > configuration has been transformed into beandefinitions accordingly. Then, each BeanDefinition has been registered to the registry, and the registration event has been sent.

At this point, the obtainFreshBeanFactory() method officially ends.

spring's calling process link is very, very long. You get lost after clicking in step by step. Tian believes that a better way is to stand outside the method to see what the method does, and then gradually split it into each method.

Stand outside refresh() and look at the two methods. prepareRefresh() prepares for the refresh. obtainFreshBeanFactory() registers the bean and adds it to beanfactory.

Well, that's all for today's spring source code analysis.

Topics: Spring Spring Boot