SpringBoot启动过程中,候选类的过滤和加载

几个初始化要点:
在调用SpringApplication的构造函数时,调用了setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class))方法时,底层调用了loadSpringFactories方法,加载了spring.factories下的类 ,并进行了缓存 ,如下,然后将加载到的初始化类型的类放入了list容器中,供后面调用

	private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
		Map<String, List<String>> result = cache.get(classLoader);
		if (result != null) {
			return result;
		}

		result = new HashMap<>();
		try {
			Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				UrlResource resource = new UrlResource(url);
				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
				for (Map.Entry<?, ?> entry : properties.entrySet()) {
					String factoryTypeName = ((String) entry.getKey()).trim();
					String[] factoryImplementationNames =
							StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
					for (String factoryImplementationName : factoryImplementationNames) {
						result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
								.add(factoryImplementationName.trim());
					}
				}
			}

			// Replace all lists with unmodifiable lists containing unique elements
			result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
					.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
			cache.put(classLoader, result);
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load factories from location [" +
					FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
		return result;
	}

SpringBoot在启动的过程中,加载到主类后,根据主类上配置的注解信息,由ConfigurationClassParser对启动类进行解析,在parse的过程中,对includeFilters,excludeFilters进行了解析,添加到了类型过滤器中,而且在解析过程中,以内部类的形式,添加了一个排除过滤器,方便排除自身,在后面有用到,

接着处理包括@ComponentScan、@ComponentScans,当解析到basePackages时,对包路径下的类使用ClassPathBeanDefinitonScanner对类进行处理;将对应的类资源包装成Resource,然后对类进行类型过滤,获取到符合条件的候选型加载类。

public class ClassPathScanningCandidateComponentProvider implements EnvironmentCapable, ResourceLoaderAware {

  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);
				}
				try {
					MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
                                        //此处根据元信息对类进行过滤
					if (isCandidateComponent(metadataReader)) {
						ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
						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 (FileNotFoundException ex) {
					if (traceEnabled) {
						logger.trace("Ignored non-readable " + resource + ": " + ex.getMessage());
					}
				}
				catch (Throwable ex) {
					throw new BeanDefinitionStoreException(
							"Failed to read candidate component class: " + resource, ex);
				}
			}
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
		}
		return candidates;
	}

        //此处根据元数据信息对类进行过滤
	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;
	}
}


tf.match(metadataReader, getMetadataReaderFactory()),方法首先对自身做了判断,如果等于自身,则排除掉。默认的排除过滤器,包括自身创建的内部类,AutoConfigurationExcludeFilter、TypeExcludeFilter三个排除过滤器
默认的包含过滤器包括两个注解类型分别为@Component和@ManagedBean的AnnotationTypeFilter

	public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
			throws IOException {

		// This method optimizes avoiding unnecessary creation of ClassReaders
		// as well as visiting over those readers.

		if (matchSelf(metadataReader)) {
			return true;
		}
		ClassMetadata metadata = metadataReader.getClassMetadata();
		if (matchClassName(metadata.getClassName())) {
			return true;
		}

		if (this.considerInherited) {
			String superClassName = metadata.getSuperClassName();
			if (superClassName != null) {
				// Optimization to avoid creating ClassReader for super class.
				Boolean superClassMatch = matchSuperClass(superClassName);
				if (superClassMatch != null) {
					if (superClassMatch.booleanValue()) {
						return true;
					}
				}
				else {
					// Need to read super class to determine a match...
					try {
						if (match(metadata.getSuperClassName(), metadataReaderFactory)) {
							return true;
						}
					}
					catch (IOException ex) {
						if (logger.isDebugEnabled()) {
							logger.debug("Could not read super class [" + metadata.getSuperClassName() +
									"] of type-filtered class [" + metadata.getClassName() + "]");
						}
					}
				}
			}
		}

		if (this.considerInterfaces) {
			for (String ifc : metadata.getInterfaceNames()) {
				// Optimization to avoid creating ClassReader for super class
				Boolean interfaceMatch = matchInterface(ifc);
				if (interfaceMatch != null) {
					if (interfaceMatch.booleanValue()) {
						return true;
					}
				}
				else {
					// Need to read interface to determine a match...
					try {
						if (match(ifc, metadataReaderFactory)) {
							return true;
						}
					}
					catch (IOException ex) {
						if (logger.isDebugEnabled()) {
							logger.debug("Could not read interface [" + ifc + "] for type-filtered class [" +
									metadata.getClassName() + "]");
						}
					}
				}
			}
		}

		return false;
	}

matchSelf(metadataReader)方法想要生效,需要添加自定义方法
matchClassName(metadata.getClassName())方法调用的是自身添加的内部类,在加载候选类的时候,将自己排除在外,因为自己本身已经处于beanDefinitionMap中。
对于符合候选项的类包装成ScannedGenericBeanDefinition即一般的扫描BeanDefinition,
扫描到候选项之后,将BeanDefinition放入到map中。
在首次对@ComponentScan、@ComponentScans进行注解类的解析并加载到候选类之后,然后检查扫描的定义集是否有任何进一步的配置类,并在需要时进行递归解析,如果满足配置类,其中难点在于此处,由于内部循环调用doProcessConfigurationClass()会导致开发者晕头转向。

则继续调用ClassPathBeanDefinitonScanner进行parse处理

		
          	                // 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());
					}
				}

判断是否是配置类

	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.
			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;
			}
		}

		Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
		if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
			beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
		}
		else if (config != null || isConfigurationCandidate(metadata)) {
			beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
		}
		else {
			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;
	}

方法内部调用了isConfigurationCandidate方法用来判断元数据信息是否满足ConfigurationCandidate,并且满足是Configuration类的话,会调用hasBeanMethods方法用来判断是否包含@Bean注解

abstract class ConfigurationClassUtils {

	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...
		return hasBeanMethods(metadata);
	}
}

在解析完@ComponentScan注解之后,我们来到下一个重量级导入类功能注解@Import

	private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited)
			throws IOException {

		if (visited.add(sourceClass)) {
			for (SourceClass annotation : sourceClass.getAnnotations()) {
				String annName = annotation.getMetadata().getClassName();
				if (!annName.equals(Import.class.getName())) {
					collectImports(annotation, imports, visited);
				}
			}
			imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
		}
	}
		public Collection<SourceClass> getAnnotationAttributes(String annType, String attribute) throws IOException {
			Map<String, Object> annotationAttributes = this.metadata.getAnnotationAttributes(annType, true);
			if (annotationAttributes == null || !annotationAttributes.containsKey(attribute)) {
				return Collections.emptySet();
			}
			String[] classNames = (String[]) annotationAttributes.get(attribute);
			Set<SourceClass> result = new LinkedHashSet<>();
			for (String className : classNames) {
				result.add(getRelated(className));
			}
			return result;
		}

通过循环获取,获取到了多个内部类配置的@Import
此处加载到的源类是根据注解递归获取的。根据启动类@SpringBootApplication加载到的源类有

0 = {ConfigurationClassParser$SourceClass@3980} "com.bail.user.service.UserProviderBootstrap"
1 = {ConfigurationClassParser$SourceClass@4046} "org.springframework.boot.autoconfigure.SpringBootApplication"
2 = {ConfigurationClassParser$SourceClass@4017} "org.springframework.boot.SpringBootConfiguration"
3 = {ConfigurationClassParser$SourceClass@4035} "org.springframework.context.annotation.Configuration"
4 = {ConfigurationClassParser$SourceClass@3953} "java.lang.Object"
5 = {ConfigurationClassParser$SourceClass@4189} "org.springframework.boot.autoconfigure.EnableAutoConfiguration"
6 = {ConfigurationClassParser$SourceClass@4222} "org.springframework.boot.autoconfigure.AutoConfigurationPackage"
7 = {ConfigurationClassParser$SourceClass@4364} "org.springframework.context.annotation.ComponentScan"
8 = {ConfigurationClassParser$SourceClass@4497} "org.springframework.context.annotation.ImportResource"

首先是:根据源class:AutoConfigurationPackages获取到 AutoConfigurationPackages$Registrar
根据源class:AutoConfigurationPackages获取到 AutoConfigurationPackages$Registrar
根据EnableAutoConfiguration加载到AutoConfigurationImportSelector注解;
@SpringBootApplication由3个注解组成

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

}


@Configuration
@Indexed
public @interface SpringBootConfiguration {
}

@Component
public @interface Configuration {
}

@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)//自动配置选择导入类
public @interface EnableAutoConfiguration {

}

//自动配置包注册类
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
}

@Repeatable(ComponentScans.class)
public @interface ComponentScan {
}

进过getImports()方法后,加载到的类有如下两个类:

0 = {ConfigurationClassParser$SourceClass@4618} "org.springframework.boot.autoconfigure.AutoConfigurationPackages$Registrar"
1 = {ConfigurationClassParser$SourceClass@4619} "org.springframework.boot.autoconfigure.AutoConfigurationImportSelector"

然后对加载到的类进行解析processImports
AutoConfigurationPackages$Registrar符合ImportBeanDefinitionRegistrar.class,创建AutoConfigurationPackages$Registrar实例对象,随后在map容器中放入了value=启动类的ImportBeanDefinitionRegistrar;
AutoConfigurationImportSelector符合ImportSelector类,创建AutoConfigurationImportSelector实例selector之后,调用deferredImportSelectorHandler处理selector,将selector添加到了list容器中;
这个过程仅仅将实例对象放到了对应的容器中。

随后开始解析@ImportResource 注解。解析到的资源如下:

"locations" -> {String[1]@5157} ["dubbo-provider.xml"]
"reader" -> {Class@3159} "interface org.springframework.beans.factory.support.BeanDefinitionReader"
"value" -> {String[1]@5159} ["dubbo-provider.xml"]

将解析到的资源文件存储到了configClass的map容器中。

接下来继续解析@Bean注解

在解析完毕后,将解析到保存解析内容的configClass添加到configurationClasses map类型容器中。

随后调用this.deferredImportSelectorHandler.process()对importSelector进行解析。
其中,ConfigurationClassParser有多个导入类的内部类

class ConfigurationClassParser {

private static class ImportStack extends ArrayDeque<ConfigurationClass> implements ImportRegistry {

}

private class DeferredImportSelectorHandler {

}
private class DeferredImportSelectorGroupingHandler {
}
private static class DeferredImportSelectorHolder {
}
private static class DeferredImportSelectorGrouping {
}
private static class DefaultDeferredImportSelectorGroup implements Group {
}
}

内部调用了DeferredImportSelectorGroupingHandler的register对deferredImports进行处理,
在解析AutoConfigurationImportSlector的过程中,调用了一个getImports()方法,而这个方法底层调用的是SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass()方法:

```java
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
		ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
	protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
		List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
				getBeanClassLoader());
		Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
				+ "are using a custom packaging, make sure that file is correct.");
		return configurations;
	}
}
	private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
                //此处的cache中,已经缓存了spring.factories文件下要加载的不同类型的类
		Map<String, List<String>> result = cache.get(classLoader);
		if (result != null) {
			return result;
		}

		result = new HashMap<>();
		try {
			Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				UrlResource resource = new UrlResource(url);
				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
				for (Map.Entry<?, ?> entry : properties.entrySet()) {
					String factoryTypeName = ((String) entry.getKey()).trim();
					String[] factoryImplementationNames =
							StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
					for (String factoryImplementationName : factoryImplementationNames) {
						result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
								.add(factoryImplementationName.trim());
					}
				}
			}

			// Replace all lists with unmodifiable lists containing unique elements
			result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
					.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
			cache.put(classLoader, result);
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load factories from location [" +
					FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
		return result;
	}

此处我们只需要返回类型为org.springframework.boot.autoconfigure.EnableAutoConfiguration的类------------恢复内容开始------------
几个初始化要点:
在调用SpringApplication的构造函数时,调用了setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class))方法时,底层调用了loadSpringFactories方法,加载了spring.factories下的类 ,并进行了缓存 ,如下,然后将加载到的初始化类型的类放入了list容器中,供后面调用

	private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
		Map<String, List<String>> result = cache.get(classLoader);
		if (result != null) {
			return result;
		}

		result = new HashMap<>();
		try {
			Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				UrlResource resource = new UrlResource(url);
				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
				for (Map.Entry<?, ?> entry : properties.entrySet()) {
					String factoryTypeName = ((String) entry.getKey()).trim();
					String[] factoryImplementationNames =
							StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
					for (String factoryImplementationName : factoryImplementationNames) {
						result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
								.add(factoryImplementationName.trim());
					}
				}
			}

			// Replace all lists with unmodifiable lists containing unique elements
			result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
					.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
			cache.put(classLoader, result);
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load factories from location [" +
					FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
		return result;
	}

SpringBoot在启动的过程中,加载到主类后,根据主类上配置的注解信息,由ConfigurationClassParser对启动类进行解析,在parse的过程中,对includeFilters,excludeFilters进行了解析,添加到了类型过滤器中,而且在解析过程中,以内部类的形式,添加了一个排除过滤器,方便排除自身,在后面有用到,

接着处理包括@ComponentScan、@ComponentScans,当解析到basePackages时,对包路径下的类使用ClassPathBeanDefinitonScanner对类进行处理;将对应的类资源包装成Resource,然后对类进行类型过滤,获取到符合条件的候选型加载类。

public class ClassPathScanningCandidateComponentProvider implements EnvironmentCapable, ResourceLoaderAware {

  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);
				}
				try {
					MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
                                        //此处根据元信息对类进行过滤
					if (isCandidateComponent(metadataReader)) {
						ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
						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 (FileNotFoundException ex) {
					if (traceEnabled) {
						logger.trace("Ignored non-readable " + resource + ": " + ex.getMessage());
					}
				}
				catch (Throwable ex) {
					throw new BeanDefinitionStoreException(
							"Failed to read candidate component class: " + resource, ex);
				}
			}
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
		}
		return candidates;
	}

        //此处根据元数据信息对类进行过滤
	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;
	}
}


tf.match(metadataReader, getMetadataReaderFactory()),方法首先对自身做了判断,如果等于自身,则排除掉。默认的排除过滤器,包括自身创建的内部类,AutoConfigurationExcludeFilter、TypeExcludeFilter三个排除过滤器
默认的包含过滤器包括两个注解类型分别为@Component和@ManagedBean的AnnotationTypeFilter

	public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
			throws IOException {

		// This method optimizes avoiding unnecessary creation of ClassReaders
		// as well as visiting over those readers.

		if (matchSelf(metadataReader)) {
			return true;
		}
		ClassMetadata metadata = metadataReader.getClassMetadata();
		if (matchClassName(metadata.getClassName())) {
			return true;
		}

		if (this.considerInherited) {
			String superClassName = metadata.getSuperClassName();
			if (superClassName != null) {
				// Optimization to avoid creating ClassReader for super class.
				Boolean superClassMatch = matchSuperClass(superClassName);
				if (superClassMatch != null) {
					if (superClassMatch.booleanValue()) {
						return true;
					}
				}
				else {
					// Need to read super class to determine a match...
					try {
						if (match(metadata.getSuperClassName(), metadataReaderFactory)) {
							return true;
						}
					}
					catch (IOException ex) {
						if (logger.isDebugEnabled()) {
							logger.debug("Could not read super class [" + metadata.getSuperClassName() +
									"] of type-filtered class [" + metadata.getClassName() + "]");
						}
					}
				}
			}
		}

		if (this.considerInterfaces) {
			for (String ifc : metadata.getInterfaceNames()) {
				// Optimization to avoid creating ClassReader for super class
				Boolean interfaceMatch = matchInterface(ifc);
				if (interfaceMatch != null) {
					if (interfaceMatch.booleanValue()) {
						return true;
					}
				}
				else {
					// Need to read interface to determine a match...
					try {
						if (match(ifc, metadataReaderFactory)) {
							return true;
						}
					}
					catch (IOException ex) {
						if (logger.isDebugEnabled()) {
							logger.debug("Could not read interface [" + ifc + "] for type-filtered class [" +
									metadata.getClassName() + "]");
						}
					}
				}
			}
		}

		return false;
	}

matchSelf(metadataReader)方法想要生效,需要添加自定义方法
matchClassName(metadata.getClassName())方法调用的是自身添加的内部类,在加载候选类的时候,将自己排除在外,因为自己本身已经处于beanDefinitionMap中。
对于符合候选项的类包装成ScannedGenericBeanDefinition即一般的扫描BeanDefinition,
扫描到候选项之后,将BeanDefinition放入到map中。
在首次对@ComponentScan、@ComponentScans进行注解类的解析并加载到候选类之后,然后检查扫描的定义集是否有任何进一步的配置类,并在需要时进行递归解析,如果满足配置类,其中难点在于此处,由于内部循环调用doProcessConfigurationClass()会导致开发者晕头转向。

则继续调用ClassPathBeanDefinitonScanner进行parse处理

		
          	                // 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());
					}
				}

判断是否是配置类

	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.
			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;
			}
		}

		Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
		if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
			beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
		}
		else if (config != null || isConfigurationCandidate(metadata)) {
			beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
		}
		else {
			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;
	}

方法内部调用了isConfigurationCandidate方法用来判断元数据信息是否满足ConfigurationCandidate,并且满足是Configuration类的话,会调用hasBeanMethods方法用来判断是否包含@Bean注解

abstract class ConfigurationClassUtils {

	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...
		return hasBeanMethods(metadata);
	}
}

在解析完@ComponentScan注解之后,我们来到下一个重量级导入类功能注解@Import

	private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited)
			throws IOException {

		if (visited.add(sourceClass)) {
			for (SourceClass annotation : sourceClass.getAnnotations()) {
				String annName = annotation.getMetadata().getClassName();
				if (!annName.equals(Import.class.getName())) {
					collectImports(annotation, imports, visited);
				}
			}
			imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
		}
	}
		public Collection<SourceClass> getAnnotationAttributes(String annType, String attribute) throws IOException {
			Map<String, Object> annotationAttributes = this.metadata.getAnnotationAttributes(annType, true);
			if (annotationAttributes == null || !annotationAttributes.containsKey(attribute)) {
				return Collections.emptySet();
			}
			String[] classNames = (String[]) annotationAttributes.get(attribute);
			Set<SourceClass> result = new LinkedHashSet<>();
			for (String className : classNames) {
				result.add(getRelated(className));
			}
			return result;
		}

通过循环获取,获取到了多个内部类配置的@Import
此处加载到的源类是根据注解递归获取的。根据启动类@SpringBootApplication加载到的源类有

0 = {ConfigurationClassParser$SourceClass@3980} "com.bail.user.service.UserProviderBootstrap"
1 = {ConfigurationClassParser$SourceClass@4046} "org.springframework.boot.autoconfigure.SpringBootApplication"
2 = {ConfigurationClassParser$SourceClass@4017} "org.springframework.boot.SpringBootConfiguration"
3 = {ConfigurationClassParser$SourceClass@4035} "org.springframework.context.annotation.Configuration"
4 = {ConfigurationClassParser$SourceClass@3953} "java.lang.Object"
5 = {ConfigurationClassParser$SourceClass@4189} "org.springframework.boot.autoconfigure.EnableAutoConfiguration"
6 = {ConfigurationClassParser$SourceClass@4222} "org.springframework.boot.autoconfigure.AutoConfigurationPackage"
7 = {ConfigurationClassParser$SourceClass@4364} "org.springframework.context.annotation.ComponentScan"
8 = {ConfigurationClassParser$SourceClass@4497} "org.springframework.context.annotation.ImportResource"

首先是:根据源class:AutoConfigurationPackages获取到 AutoConfigurationPackages$Registrar
根据源class:AutoConfigurationPackages获取到 AutoConfigurationPackages$Registrar
根据EnableAutoConfiguration加载到AutoConfigurationImportSelector注解;
@SpringBootApplication由3个注解组成

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

}


@Configuration
@Indexed
public @interface SpringBootConfiguration {
}

@Component
public @interface Configuration {
}

@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)//自动配置选择导入类
public @interface EnableAutoConfiguration {

}

//自动配置包注册类
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
}

@Repeatable(ComponentScans.class)
public @interface ComponentScan {
}

进过getImports()方法后,加载到的类有如下两个类:

0 = {ConfigurationClassParser$SourceClass@4618} "org.springframework.boot.autoconfigure.AutoConfigurationPackages$Registrar"
1 = {ConfigurationClassParser$SourceClass@4619} "org.springframework.boot.autoconfigure.AutoConfigurationImportSelector"

然后对加载到的类进行解析processImports
AutoConfigurationPackages$Registrar符合ImportBeanDefinitionRegistrar.class,创建AutoConfigurationPackages$Registrar实例对象,随后在map容器中放入了value=启动类的ImportBeanDefinitionRegistrar;
AutoConfigurationImportSelector符合ImportSelector类,创建AutoConfigurationImportSelector实例selector之后,调用deferredImportSelectorHandler处理selector,将selector添加到了list容器中;
这个过程仅仅将实例对象放到了对应的容器中。

随后开始解析@ImportResource 注解。解析到的资源如下:

"locations" -> {String[1]@5157} ["dubbo-provider.xml"]
"reader" -> {Class@3159} "interface org.springframework.beans.factory.support.BeanDefinitionReader"
"value" -> {String[1]@5159} ["dubbo-provider.xml"]

将解析到的资源文件存储到了configClass的map容器中。

接下来继续解析@Bean注解

在解析完毕后,将解析到保存解析内容的configClass添加到configurationClasses map类型容器中。

随后调用this.deferredImportSelectorHandler.process()对importSelector进行解析。
其中,ConfigurationClassParser有多个导入类的内部类

class ConfigurationClassParser {

private static class ImportStack extends ArrayDeque<ConfigurationClass> implements ImportRegistry {

}

private class DeferredImportSelectorHandler {

}
private class DeferredImportSelectorGroupingHandler {
}
private static class DeferredImportSelectorHolder {
}
private static class DeferredImportSelectorGrouping {
}
private static class DefaultDeferredImportSelectorGroup implements Group {
}
}

内部调用了DeferredImportSelectorGroupingHandler的register对deferredImports进行处理,
在解析AutoConfigurationImportSlector的过程中,调用了一个getImports()方法,而这个方法底层调用的是SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass()方法:

```java
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
		ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
	protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
		List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
				getBeanClassLoader());
		Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
				+ "are using a custom packaging, make sure that file is correct.");
		return configurations;
	}
}
	private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
                //此处的cache中,已经缓存了spring.factories文件下要加载的不同类型的类
		Map<String, List<String>> result = cache.get(classLoader);
		if (result != null) {
			return result;
		}

		result = new HashMap<>();
		try {
			Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				UrlResource resource = new UrlResource(url);
				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
				for (Map.Entry<?, ?> entry : properties.entrySet()) {
					String factoryTypeName = ((String) entry.getKey()).trim();
					String[] factoryImplementationNames =
							StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
					for (String factoryImplementationName : factoryImplementationNames) {
						result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
								.add(factoryImplementationName.trim());
					}
				}
			}

			// Replace all lists with unmodifiable lists containing unique elements
			result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
					.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
			cache.put(classLoader, result);
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load factories from location [" +
					FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
		return result;
	}

此处我们只需要返回类型为org.springframework.boot.autoconfigure.EnableAutoConfiguration的类
在加载完自动装配类后,后序调用了加载自动装配类的过滤器,默认包括3个

org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
org.springframework.boot.autoconfigure.condition.OnClassCondition,\
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition

这些过滤条件发挥作用是基于自动装配类上的注解条件,而在过滤的时候,默认是从spring下面的配置文件中,加载相关元注解信息,文件内容位于spring-autoconfigure-metadata.properties文件里面,默认加载了有773个。
根据类名+过滤条件当做key 如:org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration+ConditionalOnClass=org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration.ConditionalOnClass,
在此项目中,进过条件过滤后,满足条件的配置类 Configuration有25个

0 = "org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration"
1 = "org.springframework.boot.autoconfigure.aop.AopAutoConfiguration"
2 = "org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration"
3 = "org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration"
4 = "org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration"
5 = "org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration"
6 = "org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration"
7 = "org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration"
8 = "org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration"
9 = "org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration"
10 = "org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration"
11 = "org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration"
12 = "org.springframework.boot.autoconfigure.sql.init.SqlInitializationAutoConfiguration"
13 = "org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration"
14 = "org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration"
15 = "org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration"
16 = "org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration"
17 = "org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration"
18 = "org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration"
19 = "org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration"
20 = "org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration"
21 = "org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration"
22 = "org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration"
23 = "org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration"
24 = "com.alibaba.boot.dubbo.autoconfigure.DubboAutoConfiguration"

此处着重分析DubboAutoConfiguration的加载,在对DubboAutoConfiguration配置类进行解析的时候,解析到 DubboAutoConfiguration包含三个Bean实例

0 = {SimpleMethodMetadata@13417} "com.alibaba.boot.dubbo.autoconfigure.DubboAutoConfiguration.serviceAnnotationBeanPostProcessor(org.springframework.core.env.Environment)"
1 = {SimpleMethodMetadata@13418} "com.alibaba.boot.dubbo.autoconfigure.DubboAutoConfiguration.relaxedDubboConfigBinder()"
2 = {SimpleMethodMetadata@13419} "com.alibaba.boot.dubbo.autoconfigure.DubboAutoConfiguration.referenceAnnotationBeanPostProcessor()"

至此,调用parse()解析完configurations之后,需要根据Configurations加载BeanDefinition,调用方法为

	private void loadBeanDefinitionsForConfigurationClass(
			ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {

		if (trackedConditionEvaluator.shouldSkip(configClass)) {
			String beanName = configClass.getBeanName();
			if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
				this.registry.removeBeanDefinition(beanName);
			}
			this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
			return;
		}

		if (configClass.isImported()) {
			registerBeanDefinitionForImportedConfigurationClass(configClass);
		}
		for (BeanMethod beanMethod : configClass.getBeanMethods()) {
			loadBeanDefinitionsForBeanMethod(beanMethod);
		}

		loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
		loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
	}

	private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
		registrars.forEach((registrar, metadata) ->
				registrar.registerBeanDefinitions(metadata, this.registry, this.importBeanNameGenerator));
	}

在解析dubbo_provider.xml时,使用了DefaultNamespaceHandlerResolver解析器,DefaultNamespaceHandlerResolver在初始化的时候,传入了handler的文件位置

	/**
	 * The location to look for the mapping files. Can be present in multiple JAR files.
	 */
	public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers";

使用了自定义的NamespaceHandler进行解析node节点,通过获取对应的DubboBeanDefinitionParser,对对应node节点进行解析,并添加到BeanDefinitionMap容器中。
在加载完BeanDefinition后,又调用了一些BeanFactoryPostProcessor,进行处理。

内部调用会调用loadBeanDefinitionsFromRegistrars注册BeanDefinitions,内部使用ImportBeanDefinitionRegistrar注册BeanDefinition,调用了ImportBeanDefinitionRegistrar的继承类DubboConfigBindingsRegistrar来注册BeanDefinition

原文地址:https://www.cnblogs.com/nangonghui/p/15568678.html