前言
父依赖:主要是管理项目的资源过滤及插件
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.7.3version>
<relativePath/>
parent>
点进spring-boot-starter-parent,发现还有一个父依赖
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>2.7.3version>
parent>
点进spring-boot-dependencies:真正管理SpringBoot应用里面所有依赖版本的地方,SpringBoot的版本控制中心
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>2.7.3version>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
SpringBoot将所有的功能场景都抽取出来,做成一个个的starter (启动器),只需要在项目中引入这些starter即可,所有相关的依赖都会导入进来 , 用什么功能就导入什么样的场景启动器即可
默认的主启动类
//@SpringBootApplication 来标注一个主程序类 , 说明这是一个Spring Boot应用
@SpringBootApplication
public class SpringbootApplication {
public static void main(String[] args) {
//启动了一个方法,其实启动了一个服务
SpringApplication.run(SpringbootApplication.class, args);
}
}
点进@SpringBootApplication:可以看到如下
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
//······
}
点进@SpringBootConfiguration
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {
@AliasFor(
annotation = Configuration.class
)
boolean proxyBeanMethods() default true;
}
点进@EnableAutoConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
//······
}
点进AutoConfigurationImportSelector.class
// 获得候选的配置
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
//这里的getSpringFactoriesLoaderFactoryClass()方法
//返回的就是我们最开始看的启动自动导入配置文件的注解类;EnableAutoConfiguration
List<String> configurations = new ArrayList<>(
SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()));
ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()).forEach(configurations::add);
Assert.notEmpty(configurations,
"No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}
这个方法又调用了 SpringFactoriesLoader 类的静态方法!我们进入SpringFactoriesLoader类loadFactoryNames() 方法【126–1333行】
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
String factoryTypeName = factoryType.getName();
//这里它又调用了 loadSpringFactories 方法
return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}
点进 loadSpringFactories【135–169行】
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
//获得classLoader , 我们返回可以看到这里得到的就是EnableAutoConfiguration标注的类本身
Map<String, List<String>> result = cache.get(classLoader);
if (result != null) {
return result;
}
result = new HashMap<>();
try {
/*
去获取一个资源 "META-INF/spring.factories"
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
*/
Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
//将读取到的资源遍历,封装成为一个Properties
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;
}
全局搜索META-INF下的:spring.factories
IDEA全局搜索快捷键:shift+shift
spring.factories 自动配置根源所在
也可以在外部库中查找
有很多很多自动配置的文件
为什么spring boot2.7.3中找到的spring.factories与下图相差甚远?
甚至找不到WebMvcAutoConfiguration的自动装配,但却是存在这个WebMvcAutoConfiguration.java文件
本来按照狂神说的,可以在里面找到WebMvcAutoConfiguration,然后找到WebMvcAutoConfiguration.java
@SpringBootApplication
public class SpringbootApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootApplication.class, args);
}
}
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.sources = new LinkedHashSet();
this.bannerMode = Mode.CONSOLE;
this.logStartupInfo = true;
this.addCommandLineProperties = true;
this.addConversionService = true;
this.headless = true;
this.registerShutdownHook = true;
this.additionalProfiles = Collections.emptySet();
this.isCustomEnvironment = false;
this.lazyInitialization = false;
this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
this.applicationStartup = ApplicationStartup.DEFAULT;
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.bootstrapRegistryInitializers = new ArrayList(this.getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = this.deduceMainApplicationClass();
}