A preface.
In the previous article in the Spring source series, Container Startup (part 1), we parsed the constructor. This article continues with the second approach
public AnnotationConfigApplicationContext(Class
... componentClasses) {
this(a);// 2. Register related information based on the configuration class
register(componentClasses);
refresh();
}
Copy the code
Register () method parsing
After the no-argument constructor is parsed, the constructor next executes the second method:
// In our example, componentClasses is the config.class we passed in
public void register(Class
... componentClasses) {
Assert.notEmpty(componentClasses, "At least one component class must be specified");
/ / is actually entrusted to AnnotatedBeanDefinitionReader classes to register
this.reader.register(componentClasses);
}
/ / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- line -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
public void register(Class
... componentClasses) {
for(Class<? > componentClass : componentClasses) {// Delegate to the internal registerBean methodregisterBean(componentClass); }}/ / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- line -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
public void registerBean(Class
beanClass) {
// Finally see the true face of Lushan! Delegate to the internal doRegisterBean() method
doRegisterBean(beanClass, null.null.null.null);
}
Copy the code
2.1 doRegisterBean() source code parsing
The source code for doRegisterBean() is important because in Spring, all beans are injected into the container through this method! Source code as follows (high energy warning):
private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
@Nullable BeanDefinitionCustomizer[] customizers) {
/ / according to class to generate a beanDefinition, concrete type is AnnotatedGenericBeanDefinition
// In the current scenario, beanClass is the config.class passed in
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
// Determine if there are conditional annotations in the current configuration class based on the condition parser in the previous reader, and if so, determine if the registration needs to be skipped temporarily.
// Remember the conditional parser used during Scanner initialization? This is where it works!
// In the current scenario, since the Config class is not configured with any conditional, there is no need to skip registration
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
// Set the Supplier function
In the current scenario, supplier is null
abd.setInstanceSupplier(supplier);
// Parse bd ScopeMetadata. When the reader is initialized scopeMetadataResolver initialize the default AnnotationScopeMetadataResolver type
// If there is an @scope annotation on the class, scopeName and proxyNode are resolved
// scopeName (scope: singleton or prototype?)
// proxyNode (JDK or Cglib?)
// @scope is also very important!! However, the explanation will not be expanded here, and will be explained in separate chapters
// In the current scenario, Config does not have the @scope annotation, so Config here will default to singletons and no proxy technology.
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
// Set the scope of beanDefinition
// The current scenario is singleton
abd.setScope(scopeMetadata.getScopeName());
// The name of the generated bean
/ / when the reader is initialized, the default beanName generator for AnnotationBeanNameGenerator.
// We can also customize beanName generators ourselves by inheriting BeanNameGenerator if necessary. In general, the default is fine.
// The default beanName generation strategy is lowercase.
// In the current scenario, the beanName of the Config class is: ConfigString beanName = (name ! =null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
// Important!! Handles public annotations such as @lazy, @Order, @Priority, @dependson.
// The function of these annotations is very simple and I won't go into detail here.
// In the current scenario, the Config class does not have these annotations.
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
// If there are other qualified annotations, set them
// The Config class is obviously absent in the current scenario
if(qualifiers ! =null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
abd.setPrimary(true);
}
else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}
else {
abd.addQualifier(newAutowireCandidateQualifier(qualifier)); }}}// BeanDefinitionCustomizer calls back to beanDefinition
// In the current scenario, no callback processing is required
if(customizers ! =null) {
for(BeanDefinitionCustomizer customizer : customizers) { customizer.customize(abd); }}// Encapsulate beanDefinition and beanName as BDH
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
// Important!! Here, scopeMetadata is used to determine whether beanDefinition needs to be brokered. If necessary, the beanDefinition of the proxy class is generated and assigned to BDH!
// In this scenario, no proxy is required, so the BDH does not change.
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
// Register the beanDefinition represented by BDH
In this scenario, the BDS represented by the Config class are registered. After successful registration, there are seven BDS in the factory (remember the six BDS registered earlier).
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
Copy the code
3. To summarize
At this point, the config. class class has been wrapped as a BeanDefinition and added to the container. Next, we’ll break down the most important step!