指定包扫描的根路径,让 Spring 来扫描指定包及子包下的组件。不过在上面的声明中有显式的指定了两个过滤条件:
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
AutoConfigurationExcludeFilter # match
match 方法要判断两个部分:是否是一个配置类,是否是一个自动配置类;当match方法为true,返回扫描类对象,否则过滤掉?
isAutoConfiguration
private boolean isAutoConfiguration(MetadataReader metadataReader) {
//查看这个方法返回值是否包含着两个部分的数据
return getAutoConfigurations()
.contains(metadataReader.getClassMetadata().getClassName());
}
getAutoConfigurations
protected List<String> getAutoConfigurations() {
if (this.autoConfigurations == null) {
this.autoConfigurations = SpringFactoriesLoader.loadFactoryNames(
EnableAutoConfiguration.class, this.beanClassLoader);
}
return this.autoConfigurations;
}
SpringFactoriesLoader.loadFactoryNames
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
// ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
// ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryClassName = ((String) entry.getKey()).trim();
for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryClassName, factoryName.trim());
}
}
}
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
classLoader 去加载了指定常量路径下的资源: FACTORIES_RESOURCE_LOCATION ,而这个常量指定的路径实际是:META-INF/spring.factories
读取其中的数据后最终会封装到一个List中:
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
这个很大的List中就有自动装配的类和启动类,于是在先前的如下代码中进行判断
return getAutoConfigurations()
.contains(metadataReader.getClassMetadata().getClassName());
最后我们得出结论:
打了@SpringBootApplication注解后,在扫包的时候会把主启动类、自动配置类屏蔽掉!