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