springboot version:2.4.5
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
// 新建一个springboot应用,并调用run方法
return new SpringApplication(primarySources).run(args);
}
SpringBoot项目启动当然也是main方法作为主程序入口
通过 new SpringApplication 创建
// SpringApplication应用构造器
public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 入参一般为null,暂不关注
this.resourceLoader = resourceLoader;
// 断言
Assert.notNull(primarySources, "PrimarySources must not be null");
// 保存主配置类
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// (1) 判断spring web应用类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// (2) 从spring.factories中获取BootstrapRegistryInitializer实现类并保存在bootstrapRegistryInitializers中
this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories();
// (3) 获取ApplicationContextInitializer(Spring应用上下文初始化器)并保存
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// (4) 获取ApplicationListener(spring应用时间监听器)并保存
// ApplicationListener用于监听Spring发布的事件
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// (5) 推断应用引导类,属于SpringApplication构造过程的末尾动作
this.mainApplicationClass = deduceMainApplicationClass();
}
上文(1)处
// 自动判断当前工程是什么类型的application // 根据当前ClassLoader下基准class的存在性判断 static WebApplicationType deduceFromClasspath() { if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null) && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) { return WebApplicationType.REACTIVE; } for (String className : SERVLET_INDICATOR_CLASSES) { if (!ClassUtils.isPresent(className, null)) { return WebApplicationType.NONE; } } // 一般是servlet应用,也就是web应用 return WebApplicationType.SERVLET; }
上文(2)处
private List<BootstrapRegistryInitializer> getBootstrapRegistryInitializersFromSpringFactories() { ArrayList<BootstrapRegistryInitializer> initializers = new ArrayList<>(); // 获取Bootstrapper实现类并保存 getSpringFactoriesInstances(Bootstrapper.class).stream() .map((bootstrapper) -> ((BootstrapRegistryInitializer) bootstrapper::initialize)) .forEach(initializers::add); // 通过这个getSpringFactoriesInstances方法获取BootstrapRegistryInitializer // 启动过程中这个方法多次用来获取spring.factories中获取配置 initializers.addAll(getSpringFactoriesInstances(BootstrapRegistryInitializer.class)); return initializers; }
上文(5)处
private Class<?> deduceMainApplicationClass() { try { StackTraceElement[] stackTrace = new RuntimeException().getStackTrace(); for (StackTraceElement stackTraceElement : stackTrace) { if ("main".equals(stackTraceElement.getMethodName())) { // 返回main方法的类 return Class.forName(stackTraceElement.getClassName()); } } } catch (ClassNotFoundException ex) { // Swallow and continue } return null; }
// run上面2.1中创建的SpringApplication
public ConfigurableApplicationContext run(String... args) {
// 计时秒表
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// (6) 创建DefaultBootstrapContext,
// 创建过程中会调用(2)中获取到的BootstrapRegistryInitializer
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
// (7) 设置java.awt.headlerss属性,默认为true
// java系统属性,当值为true时,键盘、鼠标等图形化界面交互方式失效
configureHeadlessProperty();
// (8) 获取并保存SpringApplicationRunListener(spring应用运行时监听器)
// spring内部实现类为EventPublishingRunListener,对SpringApplication运行阶段进行事件发布
// 发布的事件可被ApplicationListener监听
// 小伙伴可以自己实现一把这个接口,监控一下启动阶段
SpringApplicationRunListeners listeners = getRunListeners(args);
// (9) 遍历调用(8)中获取到的SpringApplicationRunListeners的starting方法
// 表示spring应用刚启动
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
// (10) args是main方法的入参,在这里保存起来
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// (11) 准备环境
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
// 配置忽略的bean info (暂不知干嘛,不影响启动流程)
configureIgnoreBeanInfo(environment);
// 打印banner
// 1:getImageBanner -> 默认 banner.jpg banner.png banner.gif
// 2:getTextBanner -> 默认 banner.txt
Banner printedBanner = printBanner(environment);
// (12) 创建spring应用上下文(IOC容器)
// 根据webApplicationType创建 servlet 对应AnnotationConfigServletWebServerApplicationContext
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
// (13) Spring应用上下文(context)运行前的准备工作
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
// (14) 刷新容器 将会调用spring的容器刷新方法,进入启动阶段
refreshContext(context);
// (15) 暂时为空方法 Called after the context has been refreshed.
afterRefresh(context, applicationArguments);
// 计时秒表停止
stopWatch.stop();
// 打印启动日志
// Started xxx application in xxx seconds,(JVM running for xxx )
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
// (16) 遍历调用(8)中RunListeners的started方法
// 表示Context已启动,SpringBean已初始化完成
listeners.started(context);
// (17)获取并调用 Runners
// Runners有两种分别为ApplicationRunner和CommandLineRunner
// 两种Runner的run方法入参形式不一样,执行时机一致
// 可用来进行一次性任务执行,可作为spring启动后的执行任务
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
// (18) 捕获启动流程中的异常
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
// (19) 遍历调用(8)中Runnerlistenner的running方法
// 表示Spring应用正在运行,Congratulations!
listeners.running(context);
}
catch (Throwable ex) {
// (20) 捕获(19)中的异常,执行(18)一样的逻辑
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
return context;
}
上文(6)处
private DefaultBootstrapContext createBootstrapContext() { // 创建BootstrapContext DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext(); // 遍历调用BootstrapRegistryInitializer的初始化方法 // 执行对bootstrapContext的初始化动作 this.bootstrapRegistryInitializers.forEach((initializer) ->initializer.initialize(bootstrapContext)); return bootstrapContext; }
上文(8)处
private SpringApplicationRunListeners getRunListeners(String[] args) { // 注意这个types,这里要求spring.factories中SpringApplicationRunListeners的构造方法参数为这两个类型 // 且顺序不能错,否则不能初始化Runnerlistener Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class }; // 也是从spring.factories中获取 return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args), this.applicationStartup); }
上文(11)处
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) { // Create and configure the environment // 根据(1)中的webApplicationType创建 ConfigurableEnvironment environment = getOrCreateEnvironment(); // configure the environment 对属性源或配置文件进行细粒度控制。 configureEnvironment(environment, applicationArguments.getSourceArgs()); // 关联environment ConfigurationPropertySources.attach(environment); // 调用RunnerListener的environmentPrepared // 表示environment已经准备好了,允许你进行调整 listeners.environmentPrepared(bootstrapContext, environment); DefaultPropertiesPropertySource.moveToEnd(environment); // 配置active profile configureAdditionalProfiles(environment); bindToSpringApplication(environment); if (!this.isCustomEnvironment) { environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment, deduceEnvironmentClass()); } ConfigurationPropertySources.attach(environment); return environment; }
上文 (13) 处
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { // 设置Context的environment context.setEnvironment(environment); // ApplicationContext 的后置处理,默认注册了一个bean,影响后续beanName的生成 // SpringBoot注释明确指明这个可被子类覆盖实现,小伙伴们可实现一把 postProcessApplicationContext(context); // 遍历调用(3) 中上下文初始化器的初始化方法,对context进行初始化 applyInitializers(context); // 遍历调用(8) 中的RunListener的contextPrepared方法 // 表示Context已准备完毕,小伙伴们可以大展身手调整一下了 listeners.contextPrepared(context); // 发布了一个bootstrapContext close事件 bootstrapContext.close(context); if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } // Add boot specific singleton beans ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); // 将(10)中的启动参数对象注册为bean beanFactory.registerSingleton("springApplicationArguments", applicationArguments); // 注册springBootBanner的bean if (printedBanner != null) { beanFactory.registerSingleton("springBootBanner", printedBanner); } if (beanFactory instanceof DefaultListableBeanFactory) { // bean的Override配置,默认为false ((DefaultListableBeanFactory) beanFactory) .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } // 默认false if (this.lazyInitialization) { // 设置beanFactory的后置处理器 context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor()); } // Load the sources // @zzyang大佬:下三行代码作用: // 获取启动类并将启动引导类转换成一个BeanDefinition注册到ioc容器中 // 当context在refresh的时候就会扫描到这个BeanDefinition // 然后发现这个启动引导类的注解@SpringBootApplication,完成springboot的自动装配的功能 Set<Object> sources = getAllSources(); Assert.notEmpty(sources, "Sources must not be empty"); load(context, sources.toArray(new Object[0])); // 遍历调用(8) 中的RunListener的contextLoaded方法 // 表示Context已装载完成,但仍未启动 listeners.contextLoaded(context); }
上文 (17) 处
private void callRunners(ApplicationContext context, ApplicationArguments args) { List<Object> runners = new ArrayList<>(); // 从容器中获取ApplicationRunner的bean runners.addAll(context.getBeansOfType(ApplicationRunner.class).values()); // 从容器中获取CommandLineRunner的bean runners.addAll(context.getBeansOfType(CommandLineRunner.class).values()); // runner 进行排序,按照@Order或者Order接口排序 AnnotationAwareOrderComparator.sort(runners); // 遍历调用 for (Object runner : new LinkedHashSet<>(runners)) { // 这个地方有个神奇的设置,为什要将两个runner的回调入参设置的不一样,猜想是兼容 // 思考一下这个Runner和ApplicationStartedEvent(16)中发布的事件的区别? if (runner instanceof ApplicationRunner) { callRunner((ApplicationRunner) runner, args); } if (runner instanceof CommandLineRunner) { callRunner((CommandLineRunner) runner, args); } } }
上文 (18) 处
private void handleRunFailure(ConfigurableApplicationContext context, Throwable exception, SpringApplicationRunListeners listeners) { try { try { // 处理异常退出码 handleExitCode(context, exception); if (listeners != null) { // 遍历调用(8)中Runner的failed方法 listeners.failed(context, exception); } } finally { // 获取spring.factories中的SpringBootExceptionReporter(异常报告器) // 并调用异常分析器的reportException方法 reportFailure(getExceptionReporters(context), exception); if (context != null) { // 关闭容器 context.close(); } } } catch (Exception ex) { logger.warn("Unable to close ApplicationContext", ex); } ReflectionUtils.rethrowRuntimeException(exception); }
阶段 | 过程划分 |
---|---|
SpringApplication构造阶段 | (1):推断web应用类型 (2):加载BootstrapRegistryInitializer (3):加载ApplicationContextInitializer (4):加载ApplicationListener (5) :推断应用引导类 |
SpringApplication准备阶段 | (6):创建DefaultBootstrapContext (7):设置headless值(好像不是重点) (8):加载SpringApplicationRunListener (9):调用RunListener的starting方法 (10):保存启动参数 (11):准备Environment (12):创建ApplicationContext (13):准备ApplicationContext |
Spring应用上下文启动阶段 | (14):启动ApplicationContext |
Spring应用上下文启动后阶段 | (15):after ApplicationContext Refresh (16):调用RunListeners的started方法 (17):调用 Runners (19):调用Runlistenner的running方法 |
SpringApplication异常 | (18):捕获启动流程中的异常 (20):捕获(19)中的异常 |
简单的注释,欢迎大哥指正补充