Spring IOC source code analysis - overview of the whole link of resource location, loading, analysis and registration of annotation configuration

Set a breakpoint in the registerBeanDefinition method of DefaultListableBeanFactory, and change the entry program entry to:

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Entrance.class);

Source code: Step 1 of reading Spring source code: compiling source code and creating debugging entry

When the annotation container is started, some of the system's own beandefinitions will be registered in the system. This call stack is shallower than the previous xml call stack:

The entry is the constructor that called AnnotationConfigApplicationContext:

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
   // Call the default parameterless constructor, mainly initializing the AnnotatedBeanDefinitionReader to
   // And path scanner ClassPathBeanDefinitionScanner
   this();
   // Register the incoming Class. The Class can have @ Configuration annotation or no @ Configuration annotation
   // How to register delegates to the org.springframework.context.annotation.AnnotatedBeanDefinitionReader.register method
   // Wrap the incoming Class to generate BeanDefinition and register it in BeanDefinitionRegistry
   register(componentClasses);
   refresh();
}

At this(), the system's own BeanDefinition instance has already started to register in DefaultListableBeanFactory

The previous xml method is to register only when refresh()


Enter this():

public AnnotationConfigApplicationContext() {
   this.reader = new AnnotatedBeanDefinitionReader(this);
   this.scanner = new ClassPathBeanDefinitionScanner(this);
}

    in the actual constructor, two member variables reader and scanner will be initialized. Like the previous xmlbean definition, reader is used to parse the corresponding configuration resources, parse the corresponding BeanDefinition instances, and finally register these instances in the container of DefaultListableBeanFactory. The parameter this passed in by the constructor is the AnnotationConfigApplicationContext instance itself; A scanner is a scanner that scans a package.

   after expanding this in the parentheses, you will find that there is a built-in beanFactory, which has been created at this time. It is an instance of DefaultListableBeanFactory. In the previous xml method, it was created in the refresh() method, so the built-in container of annotations was created before xml, The reason why you want to create it in advance is that when the annotation container is started, some system built-in beandefinitions will be registered in the system, so you need to create a DefaultListableBeanFactory instance to provide the registration of these system beandefinitions.

   because the system BeanDefinition will be registered, the registerBeanDefinition method of DefaultListableBeanFactory will be executed many times. If you repeat the Resume Problem several times, you will find that the familiar custom entry instance appears

   since the entry is marked by @ Configuration, it is executing

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Entrance.class);

It will also be registered in the container. Further, it will be found that it is registered in the container through register

Register is mainly to register the business class marked by @ Configuration, and then look up the stack:

@Override
public void register(Class<?>... componentClasses) {
   Assert.notEmpty(componentClasses, "At least one component class must be specified");
   this.reader.register(componentClasses);
}

this.reader here refers to AnnotationBeanDefinitionReader. If you enter the source code of this class, you will find that it does not belong to the BeanDefinitionReader system. It is specifically responsible for processing BeanDefinition related to annotation

  this is done to distinguish annotations from other configurations. It also has a BeanDefinitionRegistry instance to delegate it to register the AnnotationBeanDefinition instance in the container.

  continue to move forward through the call stack. After the register method is empty, it will traverse the classes marked by @ Configuration and register them one by one

public void register(Class<?>... componentClasses) {
   for (Class<?> componentClass : componentClasses) {
      registerBean(componentClass);
   }
}

Go one step further and you will find the do method:

public void registerBean(Class<?> beanClass) {
   doRegisterBean(beanClass, null, null, null, null);
}

Enter the do method:
  first, wrap the corresponding class object with AnnotatedGenericBeanDefinition, and then handle other annotations defined on the class, which are the same as the attributes defined by the bean tag

After processing annotations:

// Wrap BeanDefinition with BeanDefinitionHolder
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
// This line of code is related to dynamic proxy and scope annotation, mainly to see whether dynamic proxy objects are generated according to Spring's scope
// However, in this case, no operation is done, but the passed in definitionHolder is returned
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
// Register the scanned Bean with the container
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);


Then, just like xml, go to BeanDefinitionReaderUtils and call the registerBeanDefinition method to register:

Tags: Java Spring Back-end

Posted on Mon, 25 Oct 2021 09:45:45 -0400 by kath421