SpringApplication到底run了什么(上)
2019-09-30 06:48:54来源:博客园 阅读 ()
SpringApplication到底run了什么(上)
在上篇文章:SpringBoot源码解析:创建SpringApplication对象实例中,我们详细描述了SpringApplication对象实例的创建过程,本篇文章继续看
run
方法的执行逻辑吧
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模式是系统的一种配置模式。在系统可能缺少显示设备、键盘或鼠标这些外设的情况下可以使用该模式
个人理解为是一些图形相关的组件能否使用的开关,欢迎各位大佬指正
接着遍历所有构造
SpringApplication
实例时加载的SpringApplicationRunListener
,调用它们的started
方法
这里构造时仅仅加载了一个EventPublishingRunListener
类,所以咱们就来解析一下这个东东
public void starting() {
this.initialMulticaster.multicastEvent(
new ApplicationStartingEvent(this.application, this.args));
}
可以看到这里调用了SimpleApplicationEventMulticaster
类的multicastEvent
方法并且传入了ApplicationStartingEvent
对象,看名字就知道了这个是SpringBoot启动事件
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
方法,这个方法中主要就是从最启动时获取的所有监听器和这个事件做了下匹配,返回通过匹配的监听器集合
接着就是看是否设置线程池参数,如果有线程池则使用线程池的线程进行操作,否则将同步调用监听器
- 把所有的命令行启动参数封装成
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系统属性和一个操作系统环境变量的对象
配置 configureEnvironment
protected void configureEnvironment(ConfigurableEnvironment environment,
String[] args) {
// 配置PropertySources
configurePropertySources(environment, args);
// 配置Profiles
configureProfiles(environment, args);
}
分别看一下两个方法
配置PropertySources
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));
}
}
}
这里就体现出了这个命令行参数比应用配置文件的优先级高的情况了
配置Profiles
从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
对象的第一个位置放的是它自己,循环引用,这个具体的含义还有待挖掘
原文链接:https://www.cnblogs.com/zhixiang-org-cn/p/11575705.html
如有疑问请与原作者联系
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
上一篇:旅行商问题分析(分支限界法)
下一篇:浅谈JVM
- 5月到6月程序员到底经历了和什么,工资狂跌***元,你是否也 2020-06-10
- 计算机基础到底是哪些基础?为什么很重要! 2020-06-08
- 到底是程序员的世界有 10 种人,你是哪一种?看懂的都是老司 2020-06-02
- 天天在用Redis,那你对Redis的AOF持久化到底了解多少呢? 2020-05-30
- 【报错】导入项目后报错:Target runtime Apache Tomcat v7. 2020-05-25
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash