二、SpringApplication.run(String... args)方法解析
public ConfigurableApplicationContext run(String... args) { // 1.创建一个计时器,并启动计时器 StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); // 2.配置java.awt.headless=true configureHeadlessProperty(); // 3.创建发布事件的监听器,用于向ApplicationListener监听器发布不同消息 SpringApplicationRunListeners listeners = getRunListeners(args); // 4.发布启动事件 listeners.starting(); try { // 5.封装args参数 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); // 6.(*)加载环境参数 ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); // 7. configureIgnoreBeanInfo(environment); // 8.创建banner,并打印banner Banner printedBanner = printBanner(environment); // 9.创建spring容器 context = createApplicationContext(); // 10.创建异常报告类 exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); // 11.spring容器刷新前处理 prepareContext(context, environment, listeners, applicationArguments, printedBanner); // 12.刷新spring容器 refreshContext(context); // 13.spring容器刷新后处理 afterRefresh(context, applicationArguments); // 14.停止计时器 stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } // 15.发布spring容器启动完成事件 listeners.started(context); // 16. callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try { listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } return context; }
1.1 stopWatch.start()分析
public void start(String taskName) throws IllegalStateException { if (this.currentTaskName != null) { throw new IllegalStateException("Can't start StopWatch: it's already running"); } this.currentTaskName = taskName; // 记录当前时间毫秒值 this.startTimeMillis = System.currentTimeMillis(); }
分析:
记录当前时间的毫秒值,用于计算启动spring容器时耗时
1.2 配置headless系统变量参数
private void configureHeadlessProperty() { System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless))); }
1.3 创建发布事件的监听器
private SpringApplicationRunListeners getRunListeners(String[] args) { Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class }; // 1. 加载SpringApplicationRunListener对象 // 2. 创建SpringApplicationRunListeners对象,统一管理SpringApplicationRunListener对象 return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)); }
分析:
也是通过加载/META-INF/spring.factories中的配置类,创建EventPublishingRunListener时,将所有ApplicationListener交给其管理,并创建了SimpleApplicationEventMulticaster(*)类,它是真正发布事件的类
- EventPublishingRunListener
1.4 发布启动事件(SimpleApplicationEventMulticaster)
public void starting() { this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args)); }
1.5 封装args参数
public CommandLineArgs parse(String... args) { CommandLineArgs commandLineArgs = new CommandLineArgs(); // 解析命令行中的参数 for (String arg : args) { // 解析格式为: // --spring.application.name=student // --spring.application.name student // --name if (arg.startsWith("--")) { String optionText = arg.substring(2, arg.length()); String optionName; String optionValue = null; if (optionText.contains("=")) { optionName = optionText.substring(0, optionText.indexOf('=')); optionValue = optionText.substring(optionText.indexOf('=')+1, optionText.length()); } else { optionName = optionText; } if (optionName.isEmpty() || (optionValue != null && optionValue.isEmpty())) { throw new IllegalArgumentException("Invalid argument syntax: " + arg); } // 将解析出来的键值对存放到commandLineArgs中的map中 commandLineArgs.addOptionArg(optionName, optionValue); } // 解析格式为: // aaa else { // 解析非--前缀的命令,添加到commandLineArgs中list中 commandLineArgs.addNonOptionArg(arg); } } return commandLineArgs; }
分析:解析命令行的参数,并封装到CommandLineArgs对象中
public PropertySource(String name, T source) { Assert.hasText(name, "Property source name must contain at least one character"); Assert.notNull(source, "Property source must not be null"); // 默认传的名称为:commandLineArgs this.name = name; // 上一步解析出来的CommandLineArgs对象 this.source = source; }
分析:封装解析出来的命令行参数CommandLineArgs到PropertySource(父类)->Source(子类)
public DefaultApplicationArguments(String[] args) { Assert.notNull(args, "Args must not be null"); this.source = new Source(args); this.args = args; }
分析:再一次将Source和未解析的args封装到DefaultApplicationArguments中
1.6 加载环境变量
private ConfigurableEnvironment prepareEnvironment( SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { // 获取配置环境,根据spring容器类型创建相应的StandardServletEnvironment ConfigurableEnvironment environment = getOrCreateEnvironment(); // 给environment.propertyResolver设置ConversionService // 添加命令行参数到environment.propertySource // 配置environment.activeProfiles configureEnvironment(environment, applicationArguments.getSourceArgs()); // 发布ApplicationEnvironmentPreparedEvent事件 listeners.environmentPrepared(environment); bindToSpringApplication(environment); if (!this.isCustomEnvironment) { environment = new EnvironmentConverter(getClassLoader()) .convertEnvironmentIfNecessary(environment, deduceEnvironmentClass()); } ConfigurationPropertySources.attach(environment); return environment; }