SpringBoot 源码解析5:ConfigurationClassPostProcessor整体流程和@ComponentScan源码分析

1. 知道以下几点,读ConfigurationClassPostProcessor源码会更轻松

  1. 配置类后置处理器ConfigurationClassPostProcessor,是对Spring注解式配置支持的核心,负责对@Component、@ComponentScan、@Import等注解的解析,将BeanDefinition注册到beanFactory。
  2. ConfigurationClassPostProcessor是在AnnotationConfigServletWebServerApplicationContext创建的时候注册的。参考 SpringBoot 源码解析2:启动流程
//AnnotationConfigUtils#registerAnnotationConfigProcessors
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
	RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
	def.setSource(source);
	beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
  1. BeanDefinitionRegistryPostProcessor实现了BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor。ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry在刷新容器的时候AbstractApplicationContext#invokeBeanFactoryPostProcessors方法中调用。参考 SpringBoot 源码解析4:refresh 方法解析

2. 源码解析 ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
	int registryId = System.identityHashCode(registry);
	if (this.registriesPostProcessed.contains(registryId)) {
		throw new IllegalStateException(
				"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
	}
	if (this.factoriesPostProcessed.contains(registryId)) {
		throw new IllegalStateException(
				"postProcessBeanFactory already called on this post-processor against " + registry);
	}
	this.registriesPostProcessed.add(registryId);

	processConfigBeanDefinitions(registry);
}

registry其实就是就是beanFactory,一个beanFactory只会处理一次

2.1 ConfigurationClassPostProcessor#processConfigBeanDefinitions

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
	//存放有@Configuration的BeanDefinitionHolder
	List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
	//获取到手动注册的BeanDefinition,在此之前已经将启动类注册了,请参考springBoot启动流程
	String[] candidateNames = registry.getBeanDefinitionNames();

	for (String beanName : candidateNames) {
		BeanDefinition beanDef = registry.getBeanDefinition(beanName);
		//判断BeanDefinition是否存在ConfigurationClassPostProcessor.configurationClass属性
		if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
			if (logger.isDebugEnabled()) {
				logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
			}
		}
		// 不存在ConfigurationClassPostProcessor.configurationClass,就会配置此属性。
		// 配置里@Configuration就会返回true,才会放入到候选配置里面
		else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
			configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
		}
	}

	// Return immediately if no @Configuration classes were found
	// 没有发现@Configuration,就会立马返回
	if (configCandidates.isEmpty()) {
		return;
	}

	// Sort by previously determined @Order value, if applicable
	// 按照@Order排序
	configCandidates.sort((bd1, bd2) -> {
		int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
		int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
		return Integer.compare(i1, i2);
	});

	// Detect any custom bean name generation strategy supplied through the enclosing application context
	// 探测有没有自定义的BeanName生成器,如果有的话就使用自定义的beanName生成器
	SingletonBeanRegistry sbr = null;
	if (registry instanceof SingletonBeanRegistry) {
		sbr = (SingletonBeanRegistry) registry;
		if (!this.localBeanNameGeneratorSet) {
			BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
					AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
			if (generator != null) {
				this.componentScanBeanNameGenerator = generator;
				this.importBeanNameGenerator = generator;
			}
		}
	}

	if (this.environment == null) {
		this.environment = new StandardEnvironment();
	}

	// Parse each @Configuration class
	// 创建解析器,解析每一个有@Configuration的类
	ConfigurationClassParser parser = new ConfigurationClassParser(
			this.metadataReaderFactory, this.problemReporter, this.environment,
			this.resourceLoader, this.componentScanBeanNameGenerator, registry);

	Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
	Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
	do {
		// 解析有@Configuration的BeanDefinition
		parser.parse(candidates);
		// 对Configuration和Bean注解进行了校验
		parser.validate();

		Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
		configClasses.removeAll(alreadyParsed);

		// Read the model and create bean definitions based on its content
		if (this.reader == null) {
			this.reader = new ConfigurationClassBeanDefinitionReader(
					registry, this.sourceExtractor, this.resourceLoader, this.environment,
					this.importBeanNameGenerator, parser.getImportRegistry());
		}
		// 此时有一些BeanDefinition没有被注册,比如@Bean、@Import中的ImportBeanDefinitionRegistrar
		this.reader.loadBeanDefinitions(configClasses);
		alreadyParsed.addAll(configClasses);

		candidates.clear();
		// 这是在一个循环里面,判断bean工厂在解析前和解析后是否有新注册的BeanDefinition
		// 如果有新注册的BeanDefinition,那么这些BeanDefinition也有可能是配置类,就会去解析这些BeanDefinition
		if (registry.getBeanDefinitionCount() > candidateNames.length) {
			String[] newCandidateNames = registry.getBeanDefinitionNames();
			Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
			Set<String> alreadyParsedClasses = new HashSet<>();
			for (ConfigurationClass configurationClass : alreadyParsed) {
				alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
			}
			for (String candidateName : newCandidateNames) {
				if (!oldCandidateNames.contains(candidateName)) {
					BeanDefinition bd = registry.getBeanDefinition(candidateName);
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
							!alreadyParsedClasses.contains(bd.getBeanClassName())) {
						candidates.add(new BeanDefinitionHolder(bd, candidateName));
					}
				}
			}
			candidateNames = newCandidateNames;
		}
	}
	while (!candidates.isEmpty());

	// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
	if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
		sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
	}

	if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
		// Clear cache in externally provided MetadataReaderFactory; this is a no-op
		// for a shared cache since it'll be cleared by the ApplicationContext.
		((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
	}
}
  1. 获取到所有注册到的BeanDefinition,通过ConfigurationClassPostProcessor.configurationClass属性,判断BeanDefinition有没有被处理过。下面会讲ConfigurationClassUtils#checkConfigurationClassCandidate。
  2. 如果没有处理,那么就会调用 ConfigurationClassUtils#checkConfigurationClassCandidate判断当前的BeanDefinition是否为配置类。只有当它为配置类,后面的配置类解析器才会对它进行解析。
  3. 兼容了自定义的Bean的名称生成器,可以使用用户自定义的生成器。
  4. 创建配置类解析器ConfigurationClassParser,对已排好序的BeanDefinitionHolder进行解析。
  5. 对Configuration和Bean注解进行一些校验。
  6. 判断bean工厂在解析前和解析后是否有新注册的BeanDefinition。如果有新注册的BeanDefinition,这些BeanDefinition有可能是配置类,那么就会通过ConfigurationClassParser去解析这些BeanDefinition。
2.1.1 ConfigurationClassUtils#checkConfigurationClassCandidate
校验当前的BeanDefinition是否为配置类
public static boolean checkConfigurationClassCandidate(
		BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {

	String className = beanDef.getBeanClassName();
	if (className == null || beanDef.getFactoryMethodName() != null) {
		return false;
	}

	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.
		// 这些类型Spring不可作为配置类
		Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
		if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
				BeanPostProcessor.class.isAssignableFrom(beanClass) ||
				AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
				EventListenerFactory.class.isAssignableFrom(beanClass)) {
			return false;
		}
		metadata = AnnotationMetadata.introspect(beanClass);
	}
	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;
		}
	}

	// 判断获取Configuration注解的属性
	Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
	if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
		// Configuration 注解的proxyBeanMethods属性为true,则为BeanDefinition为full,会被代理
		beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
	}
	// 当前的BeanDefinition"能作为配置类",配置属性为lite,不被代理
	else if (config != null || isConfigurationCandidate(metadata)) {
		beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
	}
	else {
		// Configuration注解不存在
		return false;
	}

	// It's a full or lite configuration candidate... Let's determine the order value, if any.
	Integer order = getOrder(metadata);
	if (order != null) {
		beanDef.setAttribute(ORDER_ATTRIBUTE, order);
	}

	return true;
}
  1. 判断了BeanFactoryPostProcessor、BeanPostProcessor、AopInfrastructureBean、EventListenerFactory类型不能作为配置类。
  2. 如果当前BeanDefintion没有@Configuration,就不能作为配置类。
  3. 如果有@Configuration并且proxyBeanMethods属性为true,能作为配置类,就会配置为full。为full的会被代理。
  4. 如果有@Configuration并且proxyBeanMethods属性为false,并且判断 “能作为配置类”,就会配置为lite。lite不会被代理。
  5. 这里简单提一下@Configuration代理过程,如果Configuration的proxyBeanMethods属性为true,那么当前的BeanDefinition为full,就会在ConfigurationClassPostProcessor#enhanceConfigurationClasses会创建代理类,从而创建代理对象。代理对象在调用beanMethod(@Bean方法)时,会被BeanMethodInterceptor拦截器拦截。代理拦截器的逻辑是这样的:在第一次调用beanMethod完毕后生成bean之后,会根据类名和方法名称生成一个缓存,第二次生成调用同一个beanMethod,会直接从缓存中取,而不是调用beanMethod去创建对象。
  6. 那么,什么样"能作为配置类"呢?
2.1.2 ConfigurationClassUtils#isConfigurationCandidate
private static final Set<String> candidateIndicators = new HashSet<>(8);

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

public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
	// Do not consider an interface or an annotation...
	if (metadata.isInterface()) {
		return false;
	}

	// Any of the typical annotations found?
	for (String indicator : candidateIndicators) {
		if (metadata.isAnnotated(indicator)) {
			return true;
		}
	}

	// Finally, let's look for @Bean methods...
	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;
	}
}

能作为配置类的条件:首先,接口肯定是不能作为配置类的。类上有Component、ComponentScan、Import、ImportResource,或者方法中有@Bean注解的,都能作为配置类。

2.2 ConfigurationClassParser#parse

public void parse(Set<BeanDefinitionHolder> configCandidates) {
	for (BeanDefinitionHolder holder : configCandidates) {
		BeanDefinition bd = holder.getBeanDefinition();
		try {
			if (bd instanceof AnnotatedBeanDefinition) {
				parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
			}
			else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
				parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
			}
			else {
				parse(bd.getBeanClassName(), holder.getBeanName());
			}
		}
		catch (BeanDefinitionStoreException ex) {
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanDefinitionStoreException(
					"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
		}
	}

	this.deferredImportSelectorHandler.process();
}

在解析完配置类之后,才会对deferredImportSelector进行处理。

2.2.1 ConfigurationClassParser#processConfigurationClass
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
	processConfigurationClass(new ConfigurationClass(metadata, beanName));
}

protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
	// 支持Conditional注解
	if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
		return;
	}

	ConfigurationClass existingClass = this.configurationClasses.get(configClass);
	if (existingClass != null) {
		if (configClass.isImported()) {
			if (existingClass.isImported()) {
				existingClass.mergeImportedBy(configClass);
			}
			// Otherwise ignore new imported config class; existing non-imported class overrides it.
			return;
		}
		else {
			// Explicit bean definition found, probably replacing an import.
			// Let's remove the old one and go with the new one.
			this.configurationClasses.remove(configClass);
			this.knownSuperclasses.values().removeIf(configClass::equals);
		}
	}

	// Recursively process the configuration class and its superclass hierarchy.
	SourceClass sourceClass = asSourceClass(configClass);
	do {
		sourceClass = doProcessConfigurationClass(configClass, sourceClass);
	}
	while (sourceClass != null);

	this.configurationClasses.put(configClass, configClass);
}
  1. configurationClasses中存放着已解析的配置信息,如果没有加载,则调用ConfigurationClassParser#doProcessConfigurationClass方法解析配置类,解析完毕之后放入到configurationClasses。
  2. 如果已解析并且importedBy不为空,则合并importedBy。如果不是Import,则清除缓存,重新解析。
2.2.2 ConfigurationClassParser#doProcessConfigurationClass
@Nullable
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
		throws IOException {

	// 处理@Component注解,处理当前类声明的类DeclaredClasse,因为当前类的内部类也有可能是配置类
	if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
		// Recursively process any member (nested) classes first
		processMemberClasses(configClass, sourceClass);
	}

	// Process any @PropertySource annotations
	// 处理@PropertySource 注解
	for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
			sourceClass.getMetadata(), PropertySources.class,
			org.springframework.context.annotation.PropertySource.class)) {
		if (this.environment instanceof ConfigurableEnvironment) {
			processPropertySource(propertySource);
		}
		else {
			logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
					"]. Reason: Environment must implement ConfigurableEnvironment");
		}
	}

	// Process any @ComponentScan annotations
	// 处理@ComponentScan注解 
	Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
			sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
	if (!componentScans.isEmpty() &&
			!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
		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());
			// 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)) {
					parse(bdCand.getBeanClassName(), holder.getBeanName());
				}
			}
		}
	}

	// Process any @Import annotations
	// 处理@Import注解
	processImports(configClass, sourceClass, getImports(sourceClass), true);

	// Process any @ImportResource annotations
	// 处理@ImportResource注解
	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
	// 处理@Bean注解
	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();
		}
	}

	// No superclass -> processing is complete
	return null;
}
  1. 此方法返回的是父类的资源,如果没有父类,说明类当前类已解析完毕。
  2. 对Component、PropertySource、ComponentScan、Import 、ImportResource、Bean等注解进行了解析。
  3. 我们最关心的是@ComponentScan和@Component,下面我们就对它们进行源码分析。

3. @ComponentScan 源码分析

在创建ConfigurationClassParser的时候,就创建了componentScanParser。
public ConfigurationClassParser(MetadataReaderFactory metadataReaderFactory,
		ProblemReporter problemReporter, Environment environment, ResourceLoader resourceLoader,
		BeanNameGenerator componentScanBeanNameGenerator, BeanDefinitionRegistry registry) {

	this.metadataReaderFactory = metadataReaderFactory;
	this.problemReporter = problemReporter;
	this.environment = environment;
	this.resourceLoader = resourceLoader;
	this.registry = registry;
	this.componentScanParser = new ComponentScanAnnotationParser(
			environment, resourceLoader, componentScanBeanNameGenerator, registry);
	this.conditionEvaluator = new ConditionEvaluator(registry, environment, resourceLoader);
}

3.1 ComponentScanAnnotationParser#parse

public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
	// 创建扫描器,默认配置了三个includeFilters。Component、ManagedBean、Named。
	ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
			componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);

	Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
	boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
	scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
			BeanUtils.instantiateClass(generatorClass));

	ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
	if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
		scanner.setScopedProxyMode(scopedProxyMode);
	}
	else {
		Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
		scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
	}

	scanner.setResourcePattern(componentScan.getString("resourcePattern"));

	for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
		for (TypeFilter typeFilter : typeFiltersFor(filter)) {
			scanner.addIncludeFilter(typeFilter);
		}
	}
	for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
		for (TypeFilter typeFilter : typeFiltersFor(filter)) {
			scanner.addExcludeFilter(typeFilter);
		}
	}

	boolean lazyInit = componentScan.getBoolean("lazyInit");
	if (lazyInit) {
		scanner.getBeanDefinitionDefaults().setLazyInit(true);
	}

	Set<String> basePackages = new LinkedHashSet<>();
	String[] basePackagesArray = componentScan.getStringArray("basePackages");
	for (String pkg : basePackagesArray) {
		String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
				ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
		Collections.addAll(basePackages, tokenized);
	}
	for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
		basePackages.add(ClassUtils.getPackageName(clazz));
	}
	//如果componentScan没有配置basePackages和basePackageClasses属性,那么就取声明@ComponentScan的类所对应的包名
	if (basePackages.isEmpty()) {
		basePackages.add(ClassUtils.getPackageName(declaringClass));
	}

	scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
		@Override
		protected boolean matchClassName(String className) {
			return declaringClass.equals(className);
		}
	});
	// 扫描包
	return scanner.doScan(StringUtils.toStringArray(basePackages));
}
  1. 此方法只是对扫描器进行了配置,扫描前的准备工作。
  2. ComponentScan扫描的时候有两种过滤器,excludeFilters比includeFilters优先级高:
    2.1. includeFilters:includeFilters匹配到的注册到bean工厂。
    2.2. excludeFilters:excludeFilters匹配到的不会注册到bean工厂。
  3. ClassPathBeanDefinitionScanner如果使用默认的过滤器,就会添加三个注解式的includeFilter:Component、ManagedBean、Named。
protected void registerDefaultFilters() {
	this.includeFilters.add(new AnnotationTypeFilter(Component.class));
	ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
	try {
		this.includeFilters.add(new AnnotationTypeFilter(
				((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
		logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
	}
	catch (ClassNotFoundException ex) {
		// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
	}
	try {
		this.includeFilters.add(new AnnotationTypeFilter(
				((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
		logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
	}
	catch (ClassNotFoundException ex) {
		// JSR-330 API not available - simply skip.
	}
}
  1. 如果@componentScan没有配置basePackages和basePackageClasses属性,那么就取声明@ComponentScan的class所对应的包名。

3.2 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) {
		//获取到basePackage下面所有的beanDefinition
		Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
		for (BeanDefinition candidate : candidates) {
			//解析Scope注解,默认singleton不代理
			ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
			candidate.setScope(scopeMetadata.getScopeName());
			//通过bean的名称生成器生成beanName,默认的是AnnotationBeanNameGenerator。解析Component、ManagedBean、Named的value属性。如果以上注解属性,则AnnotationBeanNameGenerator#buildDefaultBeanName创建默认的beanName,如果类名的前两个字母是大写,则是类的名称,否则就将首字母变成小写。
			String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
			if (candidate instanceof AbstractBeanDefinition) {
				//处理beanDefinition,对BeanDefinition设置了默认的属性
				postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
			}
			if (candidate instanceof AnnotatedBeanDefinition) {
				//解析公共的注解Lazy、Primary、DependsOn、Role、Description,对BeanDefinition的属性进行修改。
				AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
			}
			if (checkCandidate(beanName, candidate)) {
				BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
				//Scope代理处理,如果需要代理,则已经注册了原始的BeanDefinition,返回的是代理的BeanDifinition。
				definitionHolder =
						AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
				beanDefinitions.add(definitionHolder);
				//注册BeanDefinition
				registerBeanDefinition(definitionHolder, this.registry);
			}
		}
	}
	return beanDefinitions;
}
  1. 获取到basePackage下面所有的资源,并且解析成BeanDefinition。
  2. 对@Scope注解进行解析,判断是否需要代理,默认singleton不代理。
  3. 通过bean的名称生成器生成beanName,默认的是AnnotationBeanNameGenerator。解析Component、ManagedBean、Named的value属性,如果属性存在则属性为bean的名称;如果属性不存在,则AnnotationBeanNameGenerator#buildDefaultBeanName创建默认的beanName,如果类的shortName前两个字母是大写,则是shortName,否则就将shortName的首字母变成小写。
  4. 处理beanDefinition,对BeanDefinition设置了默认的属性。
  5. 解析公共的注解Lazy、Primary、DependsOn、Role、Description,对BeanDefinition的属性进行修改。
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
	AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
	if (lazy != null) {
		abd.setLazyInit(lazy.getBoolean("value"));
	}
	else if (abd.getMetadata() != metadata) {
		lazy = attributesFor(abd.getMetadata(), Lazy.class);
		if (lazy != null) {
			abd.setLazyInit(lazy.getBoolean("value"));
		}
	}

	if (metadata.isAnnotated(Primary.class.getName())) {
		abd.setPrimary(true);
	}
	AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
	if (dependsOn != null) {
		abd.setDependsOn(dependsOn.getStringArray("value"));
	}

	AnnotationAttributes role = attributesFor(metadata, Role.class);
	if (role != null) {
		abd.setRole(role.getNumber("value").intValue());
	}
	AnnotationAttributes description = attributesFor(metadata, Description.class);
	if (description != null) {
		abd.setDescription(description.getString("value"));
	}
}
  1. Scope代理处理,如果需要代理,则已经注册了原始的BeanDefinition,返回的是代理的BeanDifinition。
  2. 注册BeanDefinition。

3.3 ClassPathScanningCandidateComponentProvider#scanCandidateComponents

如何扫描资源,并且生成BeanDefinition的?
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);
		boolean traceEnabled = logger.isTraceEnabled();
		boolean debugEnabled = logger.isDebugEnabled();
		for (Resource resource : resources) {
			if (traceEnabled) {
				logger.trace("Scanning " + resource);
			}
			if (resource.isReadable()) {
				try {
					//获取元数据读取器,MetadataReader 负责读取资源里面的字节码内容
					MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
					//通过ComponentScan的过滤器,去扫描当前资源是否匹配。
					if (isCandidateComponent(metadataReader)) {
						ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
						sbd.setResource(resource);
						sbd.setSource(resource);
						if (isCandidateComponent(sbd)) {
							if (debugEnabled) {
								logger.debug("Identified candidate component class: " + resource);
							}
							candidates.add(sbd);
						}
						else {
							if (debugEnabled) {
								logger.debug("Ignored because not a concrete top-level class: " + resource);
							}
						}
					}
					else {
						if (traceEnabled) {
							logger.trace("Ignored because not matching any filter: " + resource);
						}
					}
				}
				catch (Throwable ex) {
					throw new BeanDefinitionStoreException(
							"Failed to read candidate component class: " + resource, ex);
				}
			}
			else {
				if (traceEnabled) {
					logger.trace("Ignored because not readable: " + resource);
				}
			}
		}
	}
	catch (IOException ex) {
		throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
	}
	return candidates;
}

1.由上述可知,componentScan解析器配置了三个默认的includeFilter。所以,有Component注解的class会被扫描到,并且生成BeanDefinition。
2. 获取到当前包下面所有的资源,通过includeFilter和excludeFilter判断是否为候选的spring组件。如果是,就会生成BeanDefinition。其中excludeFilter的优先级高。
3. 最终返回所有获选的BeanDefinition。BeanDefinition中存放了元数据读取器MetadataReader,元数据读取器负责读取资源中类的信息,注解、字段、方法等。

3.4 ClassPathScanningCandidateComponentProvider#isCandidateComponent

protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
	for (TypeFilter tf : this.excludeFilters) {
		if (tf.match(metadataReader, getMetadataReaderFactory())) {
			return false;
		}
	}
	for (TypeFilter tf : this.includeFilters) {
		if (tf.match(metadataReader, getMetadataReaderFactory())) {
			return isConditionMatch(metadataReader);
		}
	}
	return false;
}

匹配规则如下

  1. 优先匹配excludeFilter,再匹配includeFilter。
  2. 只要有一个excludeFilter匹配到,就不会添加到候选的BeanDefinition中。
  3. includeFilter匹配到了才会添加到候选的BeanDefinition,否则为非候选。

3.5 @ComponentScan源码总结

  1. ClassPathBeanDefinitionScanner对负责扫描classPath下面的资源文件。扫描的规则是通过includeFilters和excludeFilters完成的,其中注册了三个默认的注解过滤器@Component、@ManagedBean、@Named。
  2. 元数据读取器MetadataReader:有了资源文件,那么也需要一个元数据读取器去读取资源中的内容,比如判断是否有@Component注解,这个功能就是由元数据读取器完成的。
  3. 最终将资源文件和可读取资源文件的MetadataReader封装BeanDefinition,注册到了DefaultListableBeanFactory#beanDefinitionMap。

4. TODO 其他注解

其他注解后面在写,先写完主流程。

  • 23
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值