Spring Boot:【2.4.6】
Spring: 【5.3.7】
SpringApplication构造方法主流程新建一个简单的springboot项目,只导入web模块。
从入口开始分析
@SpringBootApplicationpublic class SpringboothelloApplication { public static void main(String[] args) { SpringApplication.run(SpringboothelloApplication.class, args); }}
先不用管注解@SpringBootApplication的事,点开run方法
# SpringApplication.javapublic static ConfigurableApplicationContext run(Class<?> primarySource, String..、args) { return run(new Class<?>[] { primarySource }, args);}
继续跟run方法
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) { return new SpringApplication(primarySources).run(args);}
这里new了一个SpringApplication,并且调用该实例的run方法
public SpringApplication(ResourceLoader resourceLoader, Class<?>..、primarySources) { this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new linkedHashSet<>(Arrays.asList(primarySources)); // 决议web应用类型 this.webApplicationType = WebApplicationType.deduceFromClasspath(); // 获取BootstrapRegistryInitializer并设置 this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories(); // 获取ApplicationContextInitializer并设置 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); // 获取ApplicationListener并设置 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); // 通过栈调用链决议主类 this.mainApplicationClass = deduceMainApplicationClass();}
上述方法里通过调用getSpringFactoriesInstances获取相应的工厂实例,这块是个比较重要的点。
private
上面代码出现了Spring框架的一个比较重要的类SpringFactoriesLoader,负责从classpath下的meta-INF/spring.factories下加载和实例化指定类型的工厂。
General purpose factory loading mechanism for internal use within the framework.
SpringFactoriesLoader loads and instantiates factories of a given type from “meta-INF/spring.factories” files which may be present in multiple JAR files in the classpath、The spring.factories file must be in Properties format, where the key is the fully qualified name of the interface or abstract class, and the value is a comma-separated list of implementation class names、For example:
example.MyService=example.MyServiceImpl1,example.MyServiceImpl2
where example.MyService is the name of the interface, and MyServiceImpl1 and MyServiceImpl2 are two implementations.
SpringFactoriesLoader内部持有一个cache,只读取一次,多次load的时候直接从cache读取
static final Map
关键方法如下,很简单,先从cache读,没有则从FACTORIES_RESOURCE_LOCATION加载资源,解析后放到cache中。
private static Map
构造方法内完成的事情
决议web应用类型获取BootstrapRegistryInitializer并设置获取ApplicationContextInitializer并设置获取ApplicationListener并设置通过栈调用链决议主类其中比较关键的调用链路
下图是具体代码的执行流程