1.Spring Boot版本
本文章使用的Spring Boot版本:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.7.4</version>
</parent>
2.流程图
3.Spring Boot启动类
@SpringBootApplication
public class SpringbootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootDemoApplication.class, args);
}
}
通常我们是通过Spring Boot启动类的main方法启动Spring Boot程序,我们通过main方法就能梳理出Spring Boot在启动过程中都做了哪些事情。
3.1.SpringApplication构造器
/**
* Create a new {@link SpringApplication} instance. The application context will load
* beans from the specified primary sources (see {@link SpringApplication class-level}
* documentation for details). The instance can be customized before calling
* {@link #run(String...)}.
* @param resourceLoader the resource loader to use
* @param primarySources the primary bean sources
* @see #run(Class, String[])
* @see #setSources(Set)
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
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 application的类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 设置bootstrapRegistryInitializers
this.bootstrapRegistryInitializers = new ArrayList<>(
getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 设置入口类
this.mainApplicationClass = deduceMainApplicationClass();
}
通过代码可以看到在设置Initializers和Listeners的过程中使用getSpringFactoriesInstances()方法,我们来看下具体是如何执行的。
3.1.1.getSpringFactoriesInstances()
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
// 从META-INF/spring.factories中获取对应的className
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 使用反射创建实例
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
1). 从META-INF/spring.factories中获取对应的className
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
Map<String, List<String>> result = (Map)cache.get(classLoader);
if (result != null) {
return result;
} else {
Map<String, List<String>> result = new HashMap();
try {
Enumeration<URL> urls = classLoader.getResources("META-INF/spring.factories");
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
// 代码省略
}
cache.put(classLoader, result);
return result;
} catch (IOException var14) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14);
}
}
}
2). 使用反射创建实例
private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
ClassLoader classLoader, Object[] args, Set<String> names) {
List<T> instances = new ArrayList<>(names.size());
for (String name : names) {
try {
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
T instance = (T) BeanUtils.instantiateClass(constructor, args);
instances.add(instance);
}
catch (Throwable ex) {
throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
}
}
return instances;
}
3.2.SpringApplication的run方法
/**
* Run the Spring application, creating and refreshing a new
* {@link ApplicationContext}.
* @param args the application arguments (usually passed from a Java main method)
* @return a running {@link ApplicationContext}
*/
public ConfigurableApplicationContext run(String... args) {
long startTime = System.nanoTime();
// 创建DefaultBootstrapContext
// 并执行启动初始程序方法(BootstrapRegistryInitializer.initialize())
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
// 设置java.awt.headless,可忽略
configureHeadlessProperty();
// META-INF/spring.factories获取SpringApplicationRunListener
SpringApplicationRunListeners listeners = getRunListeners(args);
// 发布ApplicationStartingEvent事件,并记录步骤
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
// 封装入参
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 准备环境
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
// 设置system.property中的属性spring.beaninfo.ignore
configureIgnoreBeanInfo(environment);
// 打印Banner
Banner printedBanner = printBanner(environment);
// 创建AnnotationConfigServletWebServerApplicationContext
// TODO
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
// 准备上下文
// 1.环境配置设置到上下文
// 2.执行ApplicationContext后置处理,设置beanName生成器,设置资源加载器
// 3.执行初始化程序,运行ApplicationContextInitializer.initialize()方法
// 4.发布ApplicationContextInitializedEvent事件
// 5.bootstrapContext发布BootstrapContextClosedEvent事件
// 6.注册bean对象springApplicationArguments
// 7.注册bean对象springBootBanner
// 8.设置不可循环依赖,设置可以重写BeanDefinition
// 9.添加懒加载的BeanFactory后置处理器
// 10.注册主函数为bean
// 11.发布ApplicationPreparedEvent事件
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
// 刷新
// 此处直接调用spring框架中AbstractApplicationContext的refresh()方法
// TODO
refreshContext(context);
// 刷新之后的操作
afterRefresh(context, applicationArguments);
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
}
// 发布ApplicationStartedEvent事件
listeners.started(context, timeTakenToStartup);
// 启动完成回调
// 1.找到所有ApplicationRunner的子类
// 2.找到所有CommandLineRunner的子类
// 3.回调执行所有找到的子类的run方法
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
listeners.ready(context, timeTakenToReady);
}
catch (Throwable ex) {
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
return context;
}
4.总结
5.更新时间
创建时间:2022/11/10 好文分享:Spring容器启动流程(源码解读)-敖丙