ok,跟了源码,当然只是简单跟一下,没有特别细的跟,这个过程可以看出这里的组件扫描只是扫描主配置类(@SpringBootApplication)所在包及其子包里面的所有组件,所以,写了例子验证一下:
在Application类包外写个Controller测试类
启动项目,进行访问,发现都是404找不到这个接口,再将这个Controller放在包里面,才可以扫描到
@Import({EnableAutoConfigurationImportSelector.class}) package org.springframework.boot.autoconfigure; import org.springframework.core.type.AnnotationMetadata; /** @deprecated */ @Deprecated public class EnableAutoConfigurationImportSelector extends AutoConfigurationImportSelector { public EnableAutoConfigurationImportSelector() { } protected boolean isEnabled(AnnotationMetadata metadata) { return this.getClass().equals(EnableAutoConfigurationImportSelector.class) ? (Boolean)this.getEnvironment().getProperty("spring.boot.enableautoconfiguration", Boolean.class, true) : true; } }主要看一下其基类AutoConfigurationImportSelector代码,看一下selectImport方法:
/**装载很多自动配置类,以全类名的方式返回一个字符数组**/ public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!this.isEnabled(annotationMetadata)) { return NO_IMPORTS; } else { try { //获取自动配置的元数据 AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader); //装载配置属性 AnnotationAttributes attributes = this.getAttributes(annotationMetadata); //通过类加载器读取所有的配置类全类名 List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes); configurations = this.removeDuplicates(configurations); configurations = this.sort(configurations, autoConfigurationMetadata); Set<String> exclusions = this.getExclusions(annotationMetadata, attributes); this.checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = this.filter(configurations, autoConfigurationMetadata); this.fireAutoConfigurationImportEvents(configurations, exclusions); return (String[])configurations.toArray(new String[configurations.size()]); } catch (IOException var6) { throw new IllegalStateException(var6); } } }AutoConfigurationMetadata信息,获取整个JavaEE体系的一些配置类,当然是Springboot集成的,比如有WebMvcAutoConfiguration自动配置类
跟一下getCandidateConfigurations方法,SpringFactoriesLoader是Spring-code工程的工厂加载类,使用SpringFactoriesLoader,需要在模块的META-INF/spring.factories文件自己配置属性,这个Properties格式的文件中的key是接口、注解、或抽象类的全名,value是以逗号 “ , “ 分隔的实现类,使用SpringFactoriesLoader可以实现将相应的实现类注入Spirng容器
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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; }loadFactoryNames方法代码,
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"; /* 将spring.factories的类都装载到Spring容器*/ public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) { String factoryClassName = factoryClass.getName(); try { //将META-INF/spring.factories文件里配置的属性都装载到Enumeration数据结构里 Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories"); ArrayList result = new ArrayList(); //遍历获取属性,然后再获取对应的配置类全类名 while(urls.hasMoreElements()) { URL url = (URL)urls.nextElement(); Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url)); String factoryClassNames = properties.getProperty(factoryClassName); result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames))); } return result; } catch (IOException var8) { throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + "META-INF/spring.factories" + "]", var8); } }