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: