Spring源码之@Component注解解析


使用

@Component的作用就是将类注入到spring容器中

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {

	/**
	 * The value may indicate a suggestion for a logical component name,
	 * to be turned into a Spring bean in case of an autodetected component.
	 * @return the suggested component name, if any (or empty String otherwise)
	 */
	String value() default "";

}

源码分析

ConfigurationClassParser#doProcessConfigurationClass方法中

//判断类上面是否有Component注解
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
	// Recursively process any member (nested) classes first
	//递归处理有@Component注解的内部类
	processMemberClasses(configClass, sourceClass, filter);
}

configClass.getMetadata()可以拿到类的元数据信息
如果类上面有@Component注解,则进行解析操作processMemberClasses

private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass,
		Predicate<String> filter) throws IOException {

	//获取该类的内部类并又包装成sourceClass对象
	Collection<SourceClass> memberClasses = sourceClass.getMemberClasses();
	if (!memberClasses.isEmpty()) {
		List<SourceClass> candidates = new ArrayList<>(memberClasses.size());
		for (SourceClass memberClass : memberClasses) {
			//如果类是候选的
			if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
					!memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
				candidates.add(memberClass);
			}
		}
		//排序
		OrderComparator.sort(candidates);
		//循环去处理每一个内部类
		for (SourceClass candidate : candidates) {
			if (this.importStack.contains(configClass)) {
				this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
			}
			else {
				this.importStack.push(configClass);
				try {
					//candidate 子  configClass 父,candidate 是 configClass的内部类
					processConfigurationClass(candidate.asConfigClass(configClass), filter);
				}
				finally {
					this.importStack.pop();
				}
			}
		}
	}
}

如果类中有内部类,那么要先拿到内部类,因为内部类上面也有可能有注解

public Collection<SourceClass> getMemberClasses() throws IOException {
	Object sourceToProcess = this.source;
	if (sourceToProcess instanceof Class) {
		Class<?> sourceClass = (Class<?>) sourceToProcess;
		try {
			//获取内部类
			Class<?>[] declaredClasses = sourceClass.getDeclaredClasses();
			List<SourceClass> members = new ArrayList<>(declaredClasses.length);
			for (Class<?> declaredClass : declaredClasses) {
				members.add(asSourceClass(declaredClass, DEFAULT_EXCLUSION_FILTER));
			}
			return members;
		}
		catch (NoClassDefFoundError err) {
			// getDeclaredClasses() failed because of non-resolvable dependencies
			// -> fall back to ASM below
			sourceToProcess = metadataReaderFactory.getMetadataReader(sourceClass.getName());
		}
	}
}

利用反射拿到类的内部类,内部类封装成SourceClass,并且加入到members中

如果有内部类,则循环内部类,判断内部类上面是否有需要处理的注解

public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
	// 如果接口或者注解返回
	if (metadata.isInterface()) {
		return false;
	}

	// @Component @ComponentScan @Import @ImportResource
	for (String indicator : candidateIndicators) {
		if (metadata.isAnnotated(indicator)) {
			return true;
		}
	}

	// 方法上面是否有@Bean注解
	try {
		return metadata.hasAnnotatedMethods(Bean.class.getName());
	}
	catch (Throwable ex) {
		if (logger.isDebugEnabled()) {
			logger.debug("Failed to introspect @Bean methods on class [" + metadata.getClassName() + "]: " + ex);
		}
		return false;
	}
}

如果内部类上面有需要处理的注解,则把SourceClass放入到候选集合candidates
在候选集合中排序
循环处理每一个类processConfigurationClass(candidate.asConfigClass(configClass), filter);
其中processConfigurationClass是注解解析的入口,所以这里相当于是一个递归操作;参数这里condidate.asConfigClass(configClass),condidate是正在处理的类,configClass是正在处理的类的外部类,封装成ConfigurationClass

public ConfigurationClass asConfigClass(ConfigurationClass importedBy) {
	if (this.source instanceof Class) {
		return new ConfigurationClass((Class<?>) this.source, importedBy);
	}
	return new ConfigurationClass((MetadataReader) this.source, importedBy);
}

外部类是放入到this.importedBy.add(importedBy);
private final Set<ConfigurationClass> importedBy = new LinkedHashSet<>(1);中的


解析流程图

解析流程图

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值