springboot启动流程、日志分析 |
您所在的位置:网站首页 › spring启动失败没有日志 › springboot启动流程、日志分析 |
springboot启动流程、日志分析
只关注info级别日志 1. 主类启动,通过调用SpringApplication#run(Class primarySource, String... args)方法启动程序 public static void main(String[] args) { SpringApplication.run(AppConfig.class, args); } 2. SpringApplication实例化、并调用run(Class[] primarySources, String[] args)方法启动 public static ConfigurableApplicationContext run(Class primarySource, String... args) { return run(new Class[] { primarySource }, args); } public static ConfigurableApplicationContext run(Class[] primarySources, String[] args) { // 创建创建 SpringApplication 对象并启动 return new SpringApplication(primarySources).run(args); } 2.1. 创建SpringApplication对象主要设置应用类型、初始化器、监听器 public SpringApplication(Class... primarySources) { this(null, primarySources); } @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)); this.webApplicationType = WebApplicationType.deduceFromClasspath(); setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); } resourceLoader:资源加载器,无默认值,此处即为null,用途参考文章:IoC 之 Spring 统一资源加载策略primarySources:主要的Java Config 类的数组,此处即为服务启动的主类cn.javadog.demo.springboot.AppConfigwebApplicationType:Web 应用类型,调用WebApplicationType#deduceFromClasspath()方法,通过classpath推断,此处即为SERVLET 具体类型取决于引入的maven依赖,如果引入的为spring-boot-starter-webflux则类型为REACTIVE,如果引入的为spring-boot-starter-web则类型为SERVLET,都为引入则为null这个属性,在下面的 createApplicationContext() 方法,将根据它的值(类型),创建不同类型的 ApplicationContext 对象,即 Spring 容器的类型不同。 private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext" }; private static final String WEBMVC_INDICATOR_CLASS = "org.springframework." + "web.servlet.DispatcherServlet"; private static final String WEBFLUX_INDICATOR_CLASS = "org." + "springframework.web.reactive.DispatcherHandler"; private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer"; private static final String SERVLET_APPLICATION_CONTEXT_CLASS = "org.springframework.web.context.WebApplicationContext"; private static final String REACTIVE_APPLICATION_CONTEXT_CLASS = "org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext"; 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; } } return WebApplicationType.SERVLET; } initializers: ApplicationContextInitializer 数组 通过 getSpringFactoriesInstances(Class type) 方法,进行获得 ApplicationContextInitializer 类型的对象数组,详细的解析,见「2.1.1 getSpringFactoriesInstances」 方法。当前只在 Spring MVC 的环境下,initializers 属性的结果如下图:逻辑比较简单,就是创建StopWatch对象,其内部有个TaskInfo内部类,记录一次任务的持续时间和任务名称,结果放在StopWatch的taskList属性里;本项目持续时间即为Spring容器初始化的时间,任务名称为空字符串 2.2.2 配置headless属性这个逻辑,可以无视,和AWT(硬件)相关 2.2.3 获得 SpringApplicationRunListener 的数组,并启动监听实际类型为SpringApplicationRunListener的实现类EventPublishingRunListener,实现 SpringApplicationRunListener、Ordered 接口,将 SpringApplicationRunListener 监听到的事件,转换成对应的 SpringApplicationEvent 事件,发布到监听器。具体作用暂时不深究 2.2.4 创建ApplicationArguments对象此处的args目前为空数组!可以通过命令行等方式设置参数 2.2.5 加载属性配置调用prepareEnvironment(...) 方法,加载属性配置。执行完成后,所有的 environment 的属性都会加载进来,包括 application.properties 和外部的属性配置,具体原理不深究,参见:《【死磕 Spring】—— 环境 & 属性:PropertySource、Environment、Profile》 根据 webApplicationType 类型,会创建不同类型的 ConfigurableEnvironment 对象主要配置environment有两大属性:propertySources和activeProfiles propertySources:根据配置的 defaultProperties、或者 JVM 启动参数,作为附加的 PropertySource 属性源,本项目都没有做配置activeProfiles:激活的profile,未指定即为空数组,可以同时指定多个 通知 SpringApplicationRunListener 的数组,环境变量已经准备完成,相关监听器会产生一些 debug 级别日志的日志,不去深究 private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { // Create and configure the environment // 创建 ConfigurableEnvironment 对象,并进行配置 ConfigurableEnvironment environment = getOrCreateEnvironment(); configureEnvironment(environment, applicationArguments.getSourceArgs()); // 通知 SpringApplicationRunListener 的数组,环境变量已经准备完成。 listeners.environmentPrepared(environment); // 绑定 environment 到 SpringApplication 上,暂时不太知道用途。 bindToSpringApplication(environment); // 如果非自定义 environment ,则根据条件转换。认情况下,isCustomEnvironment 为 false ,所以会执行这块逻辑。但是,一般情况下,返回的还是 environment 自身,所以可以无视这块逻辑先。 if (!this.isCustomEnvironment) { environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment, deduceEnvironmentClass()); } // 如果有 attach 到 environment 上的 MutablePropertySources ,则添加到 environment 的 PropertySource 中。 ConfigurationPropertySources.attach(environment); return environment; } 2.2.6 打印 Spring Banner打印的第一个日志,样式如下 具体解析见下方 2.2.8 创建异常报告器此处exceptionReporters属性如下,不做深究: 具体解析见下方 2.2.11 调用afterRefresh(...) 方法,执行 Spring容器的初始化的后置逻辑。 默认实现为空。代码如下: protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) { } 2.2.12 停止 StopWatch 统计时长 2.2.13 打印 Spring Boot 启动的时长日志。效果如下: 2.2.14 调用 SpringApplicationRunListeners#started(ConfigurableApplicationContext context) 方法,通知 SpringApplicationRunListener 的数组,Spring 容器启动完成 2.2.15 调用 SpringApplicationRunListeners#running(ConfigurableApplicationContext context) 方法,通知 SpringApplicationRunListener 的数组,Spring 容器运行中 |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |