在上篇文章:SpringBoot源码解析:建立SpringApplication对象实例中,咱们详细描述了SpringApplication对象实例的建立过程,本篇文章继续看
run
方法的执行逻辑吧java
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); //后面还有,本篇文章就解析到这。。。。 }
StopWatch
来记录开始时间java.awt.headless
环境变量,在网上了解了一下这个变量的相关信息Headless模式是系统的一种配置模式。在系统可能缺乏显示设备、键盘或鼠标这些外设的状况下可使用该模式web
我的理解为是一些图形相关的组件可否使用的开关,欢迎各位大佬指正spring
SpringApplication
实例时加载的SpringApplicationRunListener
,调用它们的started
方法这里构造时仅仅加载了一个EventPublishingRunListener
类,因此我们就来解析一下这个东东app
public void starting() { this.initialMulticaster.multicastEvent( new ApplicationStartingEvent(this.application, this.args)); }
能够看到这里调用了SimpleApplicationEventMulticaster
类的multicastEvent
方法而且传入了ApplicationStartingEvent
对象,看名字就知道了这个是SpringBoot启动事件less
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) { ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) { Executor executor = getTaskExecutor(); if (executor != null) { executor.execute(() -> invokeListener(listener, event)); } else { invokeListener(listener, event); } } }
其中获取监听器使用的是getApplicationListeners
方法,这个方法中主要就是从最启动时获取的全部监听器和这个事件作了下匹配,返回经过匹配的监听器集合this
接着就是看是否设置线程池参数,若是有线程池则使用线程池的线程进行操做,不然将同步调用监听器操作系统
ConfigurableEnvironment
对象private ConfigurableEnvironment prepareEnvironment( SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { ConfigurableEnvironment environment = getOrCreateEnvironment(); configureEnvironment(environment, applicationArguments.getSourceArgs()); listeners.environmentPrepared(environment); if (!this.webEnvironment) { environment = new EnvironmentConverter(getClassLoader()) .convertToStandardEnvironmentIfNecessary(environment); } return environment; }
getOrCreateEnvironment
方法名就很直观,有就直接获取,没有就新建命令行
private ConfigurableEnvironment getOrCreateEnvironment() { if (this.environment != null) { return this.environment; } if (this.webApplicationType == WebApplicationType.SERVLET) { return new StandardServletEnvironment(); } return new StandardEnvironment(); }
上篇文章中说过了,我们是Servlet环境,因此当前方法是返回一个StandardServletEnvironment
对象,这个对象的构造过程当中调用了customizePropertySources
方法(它父类的父类调用的)线程
protected void customizePropertySources(MutablePropertySources propertySources) { propertySources.addLast(new StubPropertySource("servletConfigInitParams")); propertySources.addLast(new StubPropertySource("servletContextInitParams")); if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) { propertySources.addLast(new JndiPropertySource("jndiProperties")); } super.customizePropertySources(propertySources); } //这是它父类的 protected void customizePropertySources(MutablePropertySources propertySources) { propertySources.addLast(new MapPropertySource("systemProperties", getSystemProperties())); propertySources.addLast(new SystemEnvironmentPropertySource("systemEnvironment", getSystemEnvironment())); }
能够看出StandardServletEnvironment
往propertySources
中添加了两个StubPropertySource
对象,而它的父类添加了一个包含java系统属性和一个操做系统环境变量的对象code
configureEnvironment
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) { // 配置PropertySources configurePropertySources(environment, args); // 配置Profiles configureProfiles(environment, args); }
分别看一下两个方法
protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) { MutablePropertySources sources = environment.getPropertySources(); if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) { // 存在默认配置将其放到最后位置 sources.addLast( new MapPropertySource("defaultProperties", this.defaultProperties)); } // 若是存在命令行参数则将原有的替换掉 if (this.addCommandLineProperties && args.length > 0) { String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME; if (sources.contains(name)) { PropertySource<?> source = sources.get(name); CompositePropertySource composite = new CompositePropertySource(name); composite.addPropertySource(new SimpleCommandLinePropertySource( "springApplicationCommandLineArgs", args)); composite.addPropertySource(source); sources.replace(name, composite); } else { // 将其放到第一位置 sources.addFirst(new SimpleCommandLinePropertySource(args)); } } }
这里就体现出了这个命令行参数比应用配置文件的优先级高的状况了
从PropertySources中查找spring.profiles.active属性,存在则将其值添加activeProfiles集合中
protected void configureProfiles(ConfigurableEnvironment environment, String[] args) { environment.getActiveProfiles(); Set<String> profiles = new LinkedHashSet<>(this.additionalProfiles); profiles.addAll(Arrays.asList(environment.getActiveProfiles())); environment.setActiveProfiles(StringUtils.toStringArray(profiles)); }
EnvirongmentPreparedEvent
事件protected void bindToSpringApplication(ConfigurableEnvironment environment) { try { Binder.get(environment).bind("spring.main", Bindable.ofInstance(this)); } catch (Exception ex) { throw new IllegalStateException("Cannot bind to SpringApplication", ex); } }
若是web环境变动为NONE则将StandardServletEnvironment
转换为StandardEnvironment
ConfigurationPropertySources.attach(environment)
public static void attach(Environment environment) { Assert.isInstanceOf(ConfigurableEnvironment.class, environment); MutablePropertySources sources = ((ConfigurableEnvironment) environment) .getPropertySources(); PropertySource<?> attached = sources.get("configurationProperties"); if (attached != null && attached.getSource() != sources) { sources.remove("configurationProperties"); attached = null; } if (attached == null) { sources.addFirst(new ConfigurationPropertySourcesPropertySource( "configurationProperties", new SpringConfigurationPropertySources(sources))); } }
最终这个sources
对象的第一个位置放的是它本身,循环引用,这个具体的含义还有待挖掘