复制
推断主应用类 private Class<?> deduceMainApplicationClass() {try {StackTraceElement[] stackTrace = (new RuntimeException()).getStackTrace();StackTraceElement[] var2 = stackTrace;int var3 = stackTrace.length;for(int var4 = 0; var4 < var3; ++var4) {StackTraceElement stackTraceElement = var2[var4];if ("main".equals(stackTraceElement.getMethodName())) {return Class.forName(stackTraceElement.getClassName());}}} catch (ClassNotFoundException var6) {}return null;}
复制
通过上面的源码我们可以看到推断主应用类是通过实例化一个运行时异常 , 并拿到该运行时异常的堆栈数组 , 然后循环遍历堆栈数组 , 判断堆栈元素的方法名是否为main
方法 , 若是则返回通过反射加载全类名后的主启动类;若是运行时异常堆栈元素中不存在main方法 , 则返回空 。SpringApplication
类实例化后就会调用run方法 , 下面我们再回到SpringApplication
类非静态的run方法源码
SpringApplication类实例run方法public ConfigurableApplicationContext run(String... args) {// new了一个 StopWatch并启动了它StopWatch stopWatch = new StopWatch();stopWatch.start();// springboot启动时使用ConfigurableApplicationContext作为BeanFactory接口的实现类ConfigurableApplicationContext context = null;// 实例化一个异常报告集合Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();// 设置系统属性java.awt.headless,默认为falsethis.configureHeadlessProperty();// 获取所有的启动监听器SpringApplicationRunListeners listeners = this.getRunListeners(args);// 遍历启动类监听器列表 , 并逐个启动listeners.starting();Collection exceptionReporters;try {// 实例化启动类命令参数ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);// 准备启动环境ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);// 配置环境中可忽略的bean信息this.configureIgnoreBeanInfo(environment);// 打印springboot项目的logo图标Banner printedBanner = this.printBanner(environment);// 创建应用上下文 , 也就是Spring IOC容器context = this.createApplicationContext();// 收集异常报告集合exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);// 准备应用上下文环境 , 会去加载配置类基于注解的bean、xml配置文件中定义的beanthis.prepareContext(context, environment, listeners, applicationArguments, printedBanner);// 刷新上下文 , 对于servlet应用程序这个方法会去创建和启动web服务器this.refreshContext(context);// 这个方法啥也没干this.afterRefresh(context, applicationArguments);// 启动完成 , 记时停止stopWatch.stop();if (this.logStartupInfo) {// 如果开启了记录启动日志 , 则记录应用程序启动过程耗时(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);}// 应用运行时监听器发布应用启动事件listeners.started(context);// 调用启动类中的任务this.callRunners(context, applicationArguments);} catch (Throwable var10) {// 启动过程发生异常则处理异常 , 并跑出IllegalStateException类型异常this.handleRunFailure(context, var10, exceptionReporters, listeners);throw new IllegalStateException(var10);}
复制
SpringApplicationRunListeners#starting方法public void starting() {Iterator var1 = this.listeners.iterator();while(var1.hasNext()) {SpringApplicationRunListener listener = (SpringApplicationRunListener)var1.next();listener.starting();}}
复制
通过上面的源码可以看到通过循环遍历启动类监听器集合中的每个启动类监听器 , 然后调用每个启动类监听器的
经验总结扩展阅读
- 一次SpringBoot版本升级,引发的血案
- 个人办理社保的流程是怎样的 个人怎么交社保
- 回门酒参加的都是谁 回门酒的流程
- 88vip双十一大额消费券领取流程2022 淘宝88vip双十一大额优惠券使用规则
- SpringBoot 03: 常用web组件 - - - 拦截器 + Servlet + 过滤器
- 房屋确权必须是户主吗 房屋确权的办理流程
- 公寓能不能抵押 房产证抵押贷款流程是什么
- SpringBoot 02: 初识SpringBoot
- 二手房网签注意事项 二手房网签流程
- 买房网签之后还有什么流程