Springboot@Configuration注解被扫面注射为bean的源码解析(二)

在Springboot中,@Configuration注解是最重要的注解之一,相当于Spring中的xml,关于Springboot源码中是如何解析@Configuration注解的。是我们这篇文章后面要探讨的内容。

在上篇文章中我们说了,通过Application类上面的@SpringBootApplication注解去解析注册BeanDefinition,如下代码ConfigurationClassParser类的doProcessConfigurationClass方法中.

				Set<BeanDefinitionHolder> scannedBeanDefinitions =
						this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
				// Check the set of scanned definitions for any further config classes and parse recursively if needed
				for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(
							holder.getBeanDefinition(), this.metadataReaderFactory)) {
						parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());
					}
				}

上面代码中,在解析了scannedBeanDefinitions后,就会进行parse方法处理,其中就有处理各种类型bean的逻辑,包括@Configuration。

一、是怎么执行parse方法的

我们看看条件判断,checkConfigurationClassCandidate方法中,

第一个判断是否通过的条件就是:

		AnnotationMetadata metadata;
		if (beanDef instanceof AnnotatedBeanDefinition &&
				className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
			// Can reuse the pre-parsed metadata from the given BeanDefinition...
			metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
		}
		else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
			// Check already loaded Class if present...
			// since we possibly can't even load the class file for this Class.
			Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
			metadata = new StandardAnnotationMetadata(beanClass, true);
		}
		else {
			try {
				MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
				metadata = metadataReader.getAnnotationMetadata();
			}
			catch (IOException ex) {
				if (logger.isDebugEnabled()) {
					logger.debug("Could not find class file for introspecting configuration annotations: " + className, ex);
				}
				return false;
			}
		}

如果是AnnotatedBeanDefinition类型或者AbstractBeanDefinition类型,则继续向下走,否则直接返回验证不通过。AnnotatedBeanDefinition类型有个子类是ScannedGenericBeanDefinition,就是通过扫描到的bean的类的类型。

第二个判断的条件:

		if (isFullConfigurationCandidate(metadata)) {
			beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
		}
		else if (isLiteConfigurationCandidate(metadata)) {
			beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
		}
		else {
			return false;
		}

第一个if语句的条件是,是否@Configuration注解的类。

第二个if语句的条件是,1.不是接口?2.类上面有在下面四个类型之中的注解

		candidateIndicators.add(Component.class.getName());
		candidateIndicators.add(ComponentScan.class.getName());
		candidateIndicators.add(Import.class.getName());
		candidateIndicators.add(ImportResource.class.getName());

3.类中方法上有@Bean注解,满足任意一个即可。

执行parse方法

如果上面两个大条件通过,则可以执行parse方法。执行的parse方法最后也是调用了doProcessConfigurationClass方法。

		// Process any @Import annotations
		processImports(configClass, sourceClass, getImports(sourceClass), true);

		// Process any @ImportResource annotations
		AnnotationAttributes importResource =
				AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
		if (importResource != null) {
			String[] resources = importResource.getStringArray("locations");
			Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
			for (String resource : resources) {
				String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
				configClass.addImportedResource(resolvedResource, readerClass);
			}
		}

		// Process individual @Bean methods
		Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
		for (MethodMetadata methodMetadata : beanMethods) {
			configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
		}

		// Process default methods on interfaces
		processInterfaces(configClass, sourceClass);

		// Process superclass, if any
		if (sourceClass.getMetadata().hasSuperClass()) {
			String superclass = sourceClass.getMetadata().getSuperClassName();
			if (superclass != null && !superclass.startsWith("java") &&
					!this.knownSuperclasses.containsKey(superclass)) {
				this.knownSuperclasses.put(superclass, configClass);
				// Superclass found, return its annotation metadata and recurse
				return sourceClass.getSuperClass();
			}
		}
在doProcessConfigurationClass方法后面会针对不同的注解,执行不同的操作。包活@Import,@ImportResource,@Bean,superClass等。

猜你喜欢

转载自blog.csdn.net/lz710117239/article/details/80720658
今日推荐