SpringBoot boot source code parsing – AutoConfigure implementation principle SpringBoot source code parsing – @aliasfor annotation annotation SpringBoot source code parsing – SpringBoot boot boot boot process @ComponentScan implementation principle SpringBoot source parsing – @value, @autoWired implementation principle SpringBoot source parsing – Tomcat, SpringMVC starts SpringBoot source parsing — Logging, Environment starts

The previous analytical SpringBoot AutoConfigure function of said article, ConfigurationClassParser# doProcessConfigurationClass method is very important, processing @ Component, Annotation @propertysources, @Componentscans, @import, @importResource, etc. Now look at the handling of the @ComponentScans annotation. Source code analysis based on Spring Boot 2.1

ConfigurationClassParser#doProcessConfigurationClass

protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
		throws IOException {

	...

	for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
			sourceClass.getMetadata(), PropertySources.class,
			org.springframework.context.annotation.PropertySource.class)) {	// # 1
		if(this.environment instanceof ConfigurableEnvironment) { processPropertySource(propertySource); }... } Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);	// # 2
	if(! componentScans.isEmpty() && ! this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {	// # 3
		for (AnnotationAttributes componentScan : componentScans) {
			// The config class is annotated with @ComponentScan -> perform the scan immediately
			Set<BeanDefinitionHolder> scannedBeanDefinitions =
					this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());	// # 4
			// Check the set of scanned definitions for any further config classes and parse recursively if needed
			for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
				BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
				if (bdCand == null) {
					bdCand = holder.getBeanDefinition();
				}
				if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {	// # 5parse(bdCand.getBeanClassName(), holder.getBeanName()); }}}}... }Copy the code

#1 Process the @propertysources annotation, obtain the corresponding PropertySources property source, and add it to the Environment. The relationship between PropertySources and Environment will be analyzed in the following article. Select * from SourceClass for ComponentScans; Take note of the Condition in the judgement Condition judgment class # 4 use ComponentScan ComponentScanAnnotationParser processing, Scan the beans in the specified directory to see if there is any ConfigurationClass left, and if so, recursively

ComponentScanAnnotationParser#parse -> ClassPathBeanDefinitionScanner#doScan

	protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
		Assert.notEmpty(basePackages, "At least one base package must be specified");
		Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
		for (String basePackage : basePackages) {
			Set<BeanDefinition> candidates = findCandidateComponents(basePackage);	// # 1
			for (BeanDefinition candidate : candidates) {
				ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
				candidate.setScope(scopeMetadata.getScopeName());
				String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
				if(candidate instanceof AbstractBeanDefinition) { postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);  //# 2
				}
				if (candidate instanceof AnnotatedBeanDefinition) {	
					AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);	// # 3
				}
				if (checkCandidate(beanName, candidate)) {	
					BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
					definitionHolder =
							AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
					beanDefinitions.add(definitionHolder);
					registerBeanDefinition(definitionHolder, this.registry);	// # 4}}}return beanDefinitions;
	}
Copy the code

> < Class name > < Class name > < Class name > < Class name > < Class name > < Class name > < Class name > < Class name > < Class name > < Class name > < Class name > < Class name > < Class name > < Class name > < Class name > < Class name > < Class name > < Class name > < Class name > Set to BeanDefinition #4 Register the scanned BeanDefinitions with Spring

ClassPathBeanDefinitionScanner#findCandidateComponents -> ClassPathScanningCandidateComponentProvider#scanCandidateComponents

private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
	Set<BeanDefinition> candidates = new LinkedHashSet<>();
	try {
		String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
				resolveBasePackage(basePackage) + '/' + this.resourcePattern;
		Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);	// # 1
		boolean traceEnabled = logger.isTraceEnabled();
		boolean debugEnabled = logger.isDebugEnabled();
		for (Resource resource : resources) {
			if (traceEnabled) {
				logger.trace("Scanning " + resource);
			}
			if (resource.isReadable()) {
				try {
					MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);		// # 2
					if (isCandidateComponent(metadataReader)) {		// # 3
						ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);	// # 4
						sbd.setResource(resource);
						sbd.setSource(resource);
						if (isCandidateComponent(sbd)) {	// # 5
							if (debugEnabled) {
								logger.debug("Identified candidate component class: " + resource);
							}
							candidates.add(sbd);	// # 6}... }Copy the code

SimpleMetadataReader Using the ASM read a class file # 3 whether scans to BeanDefinition # 4 to generate ScannedGenericBeanDefinition injection condition, The BeanDefinition implements the AnnotatedBeanDefinition interface, which uses ASM (multiplexing SimpleMetadataReader) to get annotation information for the Class. Without the JVM loading the Class AnnotatedBeanDefinition extension to BeanDefinition, you can get annotation information for the class. AnnotationMetadata according to Class notes of metadata, the standard implementation Class for StandardAnnotationMetadata, and AnnotationMetadataReadingVisitor use the visitor pattern, through the ASM for annotation information. #5 Checks whether BeanDefinition is non-interface, and non-loop depends on #6 to save the result

ClassPathScanningCandidateComponentProvider#isCandidateComponent

	protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
		for (TypeFilter tf : this.excludeFilters) {	
			if (tf.match(metadataReader, getMetadataReaderFactory())) {	// # 1
				return false; }}for (TypeFilter tf : this.includeFilters) {
			if (tf.match(metadataReader, getMetadataReaderFactory())) {	// # 2
				returnisConditionMatch(metadataReader); }}return false;
	}
Copy the code

#2 Filter beandefinitions using includeFilters

ClassPathScanningCandidateComponentProvider# registerDefaultFilters method, will add the default to includeFilter AnnotationTypeFilter, Handles @Component, @ManagedBean annotations, etc.

AnnotationTypeFilter#match -> matchSelf

protected boolean matchSelf(MetadataReader metadataReader) {
	AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();	// # 1
	return metadata.hasAnnotation(this.annotationType.getName()) ||	// # 2
			(this.considerMetaAnnotations && metadata.hasMetaAnnotation(this.annotationType.getName()));	// # 3
}
Copy the code

AnnotationType = annotationType = annotationType = annotationType = annotationType = annotationType = annotationType = annotationType = annotationType = annotationType = annotationType = annotationType = annotationType = annotationType = annotationType = annotationType = annotationType = annotationType = annotationType = annotationType = annotationType = annotationType = annotationType = annotationType = annotationType = annotationType

The @Service, @repository, and @Controller annotations all carry the @Component annotation. Step 3 returns true if these annotations are used on the Class

At this point, the @ComponentScans annotate the @Component Bea. In simple terms, Spring scans the class in the corresponding directory, generates the BeanDefinition and registers it with the Spring context. Finally construct the bean’s operation, is in AbstractApplicationContext# refresh method, called finishBeanFactoryInitialization, build the thermal load of singleton beans.

If you think this article is good, welcome to pay attention to my wechat public number, your attention is my motivation!