Spring source code reading notes (2)

Prospects for review

In the last chapter, we read super() and setConfigLocations() remember what they do.

public ClassPathXmlApplicationContext(
      String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
      throws BeansException {

   super(parent);
   setConfigLocations(configLocations);
   if (refresh) { // The last constructor passed true on the first startuprefresh(); }}Copy the code

Start by reviewing the method invocation flowchart and the class diagram at the end of the previous chapter.

In the last chapter we talked about the setConfigLocations method, and we ended up with two important points.

  1. Set the Environment in AbstractApplication
  2. A property collection is set in the environment

refresh()

According to the method invocation flowchart at the beginning, the key to Spring is in Refresh. There are 12 methods, and we’ll look at them one by one.

prepareRefresh()

The first method that immediately catches up with the Refresh method, prepareRefresh, is ready to refresh the context, as explained by the official annotations. Most likely do some preparatory operations, which can be skipped, but as a gesture of learning, we can not miss any.

/** * Prepare this context for refreshing, Setting its startup date and * active flag as well as performing any initialization of property sources. Sets its start date and active flag, and performs any initialization of the property source. * /
protected void prepareRefresh(a) {
   // Switch to active.
   // Switch to the active state.
   this.startupDate = System.currentTimeMillis();
   this.closed.set(false);
   this.active.set(true);

   if (logger.isDebugEnabled()) {
      if (logger.isTraceEnabled()) {
         logger.trace("Refreshing " + this);
      }
      else {
         logger.debug("Refreshing "+ getDisplayName()); }}// Initialize any placeholder property sources in the context environment.
   Initialize any placeholder property sources in the context.
   initPropertySources();

   // Validate that all properties marked as required are resolvable:
   // see ConfigurablePropertyResolver#setRequiredProperties
   / / verify whether all the tags for the necessary attributes to parse: please refer to the ConfigurablePropertyResolver# setRequiredProperties
   getEnvironment().validateRequiredProperties();

   // Store pre-refresh ApplicationListeners...
   // Store the pre-refresh application listener...
   if (this.earlyApplicationListeners == null) {
      this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
   }
   else {
      // Reset local application listeners to pre-refresh state.
      // Reset the local application listener to a 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...
   // Allows collection of early ApplicationEvents, published after Multicast is available...
   this.earlyApplicationEvents = new LinkedHashSet<>();
}
Copy the code

I can get a general idea of this method by translating the original comments in the code, but I have no idea what it means. I think this code can be read in sections and categorized.

First code

this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);

// Record some logs according to the debug status
if (logger.isDebugEnabled()) {
   if (logger.isTraceEnabled()) {
      logger.trace("Refreshing " + this);
   }
   else {
      logger.debug("Refreshing "+ getDisplayName()); }}Copy the code

This code is very simple, set the project startup time, do some state management, print some logs, nothing to look at.

Second code

initPropertySources();

protected void initPropertySources(a) {
   // For subclasses: do nothing by default.
}
Copy the code

This is obviously a template approach, and we came across this design pattern in the last article, so let’s briefly look at the extensions to its subclasses.

When we look at the implementation subclasses of this method, we see that they are all under the Web package, which is not what we’re going to do in this series, so we’ll skip over that. It’s good to know that Spring left a configuration here.

The third code

getEnvironment().validateRequiredProperties();

@Override
public void validateRequiredProperties(a) {
   MissingRequiredPropertiesException ex = new MissingRequiredPropertiesException();
   for (String key : this.requiredProperties) {
      if (this.getProperty(key) == null) { ex.addMissingRequiredProperty(key); }}if(! ex.getMissingRequiredProperties().isEmpty()) {throwex; }}Copy the code

So the getEnvironment method, remember, this method finally returns a StandardEnvironment, AbstractEnvironment and AbstractPropertyResolver validateRequiredProperties method, Final call things AbstractPropertyResolver validateRequiredProperties method in class. This method validates requiredProperties. RequiredProperties has size 0 because I didn’t set it. For doesn’t execute

The fourth code

if (this.earlyApplicationListeners == null) {
   this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}
else {
   // Reset local application listeners to pre-refresh state.
   // Reset the local application listener to a 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...
// Allows collection of early ApplicationEvents, published after Multicast is available...
this.earlyApplicationEvents = new LinkedHashSet<>();
Copy the code

In this code block, we found several listeners in observer mode. We don’t know what the listener does, but we can skip it and record how many listeners there are.

The prepareRefresh method ends here, but to sum up, it’s just a few preparatory actions and doesn’t make much sense.

obtainFreshBeanFactory()

Look at the obtainFreshBeanFactory method literal, is to get a BeanFactory.

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

@Override
protected final void refreshBeanFactory(a) throws BeansException {
    // First entry, false
   if (hasBeanFactory()) {
      destroyBeans();
      closeBeanFactory();
   }
   try {
      // Create a Bean factory
      DefaultListableBeanFactory beanFactory = createBeanFactory();
      beanFactory.setSerializationId(getId());
      customizeBeanFactory(beanFactory);
      loadBeanDefinitions(beanFactory);
      this.beanFactory = beanFactory;
   }
   catch (IOException ex) {
      throw new ApplicationContextException("I/O error parsing bean definition source for "+ getDisplayName(), ex); }}Copy the code

RefreshBeanFactory method since AbstractRefreshableApplicationContext, next one layer.

createBeanFactory()

protected DefaultListableBeanFactory createBeanFactory(a) {
   return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}


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

New here a DefaultListableBeanFactory object, structure of introduced into a method, this method is put back a the BeanFactory, because here we getParent is null, so the return null values, to continue to look down.

public DefaultListableBeanFactory(@Nullable BeanFactory parentBeanFactory) {
   super(parentBeanFactory);
}


public AbstractAutowireCapableBeanFactory(@Nullable BeanFactory parentBeanFactory) {
   this(a); setParentBeanFactory(parentBeanFactory); }public AbstractAutowireCapableBeanFactory(a) {
   super(a); ignoreDependencyInterface(BeanNameAware.class); ignoreDependencyInterface(BeanFactoryAware.class); ignoreDependencyInterface(BeanClassLoaderAware.class);if (NativeDetector.inNativeImage()) {
      this.instantiationStrategy = new SimpleInstantiationStrategy();
   }
   else {
      this.instantiationStrategy = newCglibSubclassingInstantiationStrategy(); }}@Override
public void setParentBeanFactory(@Nullable BeanFactory parentBeanFactory) {
   if (this.parentBeanFactory ! =null && this.parentBeanFactory ! = parentBeanFactory) {throw new IllegalStateException("Already associated with parent BeanFactory: " + this.parentBeanFactory);
   }
   if (this == parentBeanFactory) {
      throw new IllegalStateException("Cannot set parent bean factory to self");
   }
   this.parentBeanFactory = parentBeanFactory;
}
Copy the code

This looks familiar, much like the construction in the previous section, but take a look at its implementation. His no arguments ignoreDependencyInterface method according to the literal interpretation of tectonic ignore depend on the interface, the explanation is to ignore when dependency checks and autowire interface, specific didn’t enjoy what do you mean, later see, first record. Judging from the following, Spring uses Cglib’s strategy to instantiate objects, since we have no special configuration. This completes the step in instantiating the Bean factory, drawing some conclusions \

  1. Instantiation is DefaultListableBeanFactory
  2. The instantiation policy uses Cglib

customizeBeanFactory

protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
   if (this.allowBeanDefinitionOverriding ! =null) {
      beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
   }
   if (this.allowCircularReferences ! =null) {
      beanFactory.setAllowCircularReferences(this.allowCircularReferences); }}Copy the code

Assigns values to the newly created Bean factory based on the ApplicationContext’s own value. Since our ApplicationContext is empty here, we won’t go in and literally understand these two variables

  1. AllowBeanDefinitionOverriding allows Bean definitions to rewrite
  2. AllowCircularReferences allows circular references

See how these two values are used in the registry. See the word circular reference, more important.

loadBeanDefinitions

The method is loaded with the Bean definition, so I’m excited to see the information about the Bean.

protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
      throws BeansException, IOException;
Copy the code

Click on the method to see that it is an abstract method and see what methods it has implemented.

We use XML to load the ApplicationContext, so here we look at the implementation method of the implementation class.

@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
   // Create a new XmlBeanDefinitionReader for the given BeanFactory.
   XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

   // Configure the bean definition reader with this context's
   // resource loading environment.
   beanDefinitionReader.setEnvironment(this.getEnvironment());
   beanDefinitionReader.setResourceLoader(this);
   beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

   // Allow a subclass to provide custom initialization of the reader,
   // then proceed with actually loading the bean definitions.
   initBeanDefinitionReader(beanDefinitionReader);
   loadBeanDefinitions(beanDefinitionReader);
}
Copy the code

Come to an end

It’s 2:00 a.m., so I’ll stop here for this article and write more tomorrow. It’s not a good time to continue writing, so let’s take a break. So far, our class diagram is posted below.

conclusion

The purpose of writing an article is to help you consolidate your knowledge. You can point out your bad or wrong writing in the comments section. If you read the article and think it is helpful to you, you can like it. If you find some questions and have doubts, or do not understand, you can comment. Of course, I also hope to make friends with you and learn from each other.