Spring 5 source code analysis - register configuration class

Posted by svgk01 on Tue, 12 Nov 2019 21:50:18 +0100

Previous: Spring 5 source code analysis - container initialization The container has been prepared. In this article, you need to register your Java configuration class with beanDefinitionMaps, so that ConfigurationCLassPostProcessor can analyze the annotations on the Java configuration class, and check whether to execute the class conforming to the Spring rules in the package path to scan, register, instantiate, etc

Method call stack:

doRegisterBean:254, AnnotatedBeanDefinitionReader (org.springframework.context.annotation)
registerBean:147, AnnotatedBeanDefinitionReader (org.springframework.context.annotation)
register:137, AnnotatedBeanDefinitionReader (org.springframework.context.annotation)
register:183, AnnotationConfigApplicationContext (org.springframework.context.annotation)
main:12, AutowiredAnnotationMain (com.jv.spring.autowiredannotation)

Core method code comments:

	private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
			@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
			@Nullable BeanDefinitionCustomizer[] customizers) {
		//BeanDefinition generated from configuration class
		AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
		//According to whether @ Conditional wants to register this BeanDefinition, it is widely used in SpringBoot
		if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
			return;
		}

		abd.setInstanceSupplier(supplier);
		//Get the scope of the class (Scope -- singlton/prototype is defined in configurablebeanfactory)
		ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
		abd.setScope(scopeMetadata.getScopeName());
		//Generate the name of the Bean. If the name of the Bean is not specified in the annotation, it is generated in this way by default: class name - FooServiceImpl BeanName-fooServiceImpl
		String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
		//Scan and process some features of Bean, such as lazy primary dependency, etc., such as abd.setLazyInit(true)
		AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
		//At present, I only read the source code of Spring. By default, the passed qualifiers are NULL. You can change the Spring code by yourself. When calling, I will send an Annotation array containing @ Primary@Lazy
		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(new AutowireCandidateQualifier(qualifier));
				}
			}
		}
		if (customizers != null) {
			for (BeanDefinitionCustomizer customizer : customizers) {
				customizer.customize(abd);
			}
		}
		//A BeanDefinition wrapper class that places AnnotatedGenericBeanDefinition and name in the bag
		BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);

		/**
		 * In it, according to the definitionHolder.getBeanDefinition, a BeanDefinition is copied, that is, proxyBeanDefinition
		 * The original BeanDefinition resets two parameters:
		 * -autowireCandidate=0 Cannot be used for automatic injection
		 * -primary=false No longer the main Bean
		 *
		 * I don't know when I'll use it after all. It's said that Spring MVC is very useful, but it can't be used with Spring. I'll focus on the specific use scenarios and details later
		 */
		definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
		//Scan, parse and put the custom configuration class (XXXConfig.class) into the bean definition map
		BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
	}

Conclusion: put the bean definition corresponding to the Autowired annotation config defined by myself into the bean definition maps. In fact, other branch processes cannot enter. For example, the qualifiers customizers are null, so the branches involved will not be executed.

Up to now, Spring has not provided any extension points for developers to use. Next, we will slowly start to touch a lot of extension points and the logical implementation of some common annotations. Here's another chapter: Register a non @ Configuration decorated Bean directly with register(). You can get the Bean directly

Topics: Programming Spring Java SpringBoot