看springboot源码的时候感觉SpringApplication.run会被执行两次

发布于 2022-01-01 09:00:40 字数 3111 浏览 1017 评论 4

我们在启动一个springboot项目的时候会运行如下代码

public static void main(String[] args) {
	SpringApplication.run(HppaApplication.class, args);
}

这段代码的内部大概是去做了如下几件事

  • 加载系统环境变量和配置文件
  • 启动tomcat
  • 通知对应的监听器等

然后我们知道servlet3.0规范里面是说当我们web容器启动阶段会回调ServletContainerInitializer的onStartup方法。springboot中有一个ServletContainerInitializer的实现类SpringServletContainerInitializer,这个类采用

@HandlesTypes(WebApplicationInitializer.class)

这段代码注入了WebApplicationInitializer的实例,根据代码逻辑,最终会调用到SpringBootServletInitializer的onStartup方法

@Override
	public void onStartup(ServletContext servletContext) throws ServletException {
		// Logger initialization is deferred in case an ordered
		// LogServletContextInitializer is being used
		this.logger = LogFactory.getLog(getClass());
		WebApplicationContext rootAppContext = createRootApplicationContext(servletContext);
		if (rootAppContext != null) {
			servletContext.addListener(new ContextLoaderListener(rootAppContext) {

				@Override
				public void contextInitialized(ServletContextEvent event) {
					// no-op because the application context is already initialized
				}

			});
		}
		else {
			this.logger.debug("No ContextLoaderListener registered, as createRootApplicationContext() did not "
					+ "return an application context");
		}
	}

这个又调用了createRootApplicationContext方法

protected WebApplicationContext createRootApplicationContext(ServletContext servletContext) {
		SpringApplicationBuilder builder = createSpringApplicationBuilder();
		builder.main(getClass());
		ApplicationContext parent = getExistingRootWebApplicationContext(servletContext);
		if (parent != null) {
			this.logger.info("Root context already created (using as parent).");
			servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, null);
			builder.initializers(new ParentContextApplicationContextInitializer(parent));
		}
		builder.initializers(new ServletContextApplicationContextInitializer(servletContext));
		builder.contextClass(AnnotationConfigServletWebServerApplicationContext.class);
		builder = configure(builder);
		builder.listeners(new WebEnvironmentPropertySourceInitializer(servletContext));
		SpringApplication application = builder.build();
		if (application.getAllSources().isEmpty()
				&& MergedAnnotations.from(getClass(), SearchStrategy.TYPE_HIERARCHY).isPresent(Configuration.class)) {
			application.addPrimarySources(Collections.singleton(getClass()));
		}
		Assert.state(!application.getAllSources().isEmpty(),
				"No SpringApplication sources have been defined. Either override the "
						+ "configure method or add an @Configuration annotation");
		// Ensure error pages are registered
		if (this.registerErrorPageFilter) {
			application.addPrimarySources(Collections.singleton(ErrorPageFilterConfiguration.class));
		}
		return run(application);
	}

createRootApplicationContext最后一段又会去调用SpringApplication的run方法,那么是不是说明springboot应用在启动过程中,SpringApplication的run方法会被执行两次呢?这样是不是有什么问题呢?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

百思不得你姐 2022-01-07 16:07:14

但是静态方法最终还是会调用到实例方法的。 public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) { return new SpringApplication(primarySources).run(args); }

尐偏执 2022-01-05 20:54:56

一个是实例方法
public ConfigurableApplicationContext run(String... args)

一个是静态方法

public static ConfigurableApplicationContext run(Class<?> primarySource, String... args)

 

哑剧 2022-01-05 15:31:36

明白了,之前我一直以为main里面run启动的内置tomcat就会去加载SpringBootServletInitializer

沙与沫 2022-01-02 21:41:39

main里调用run启动,是jar包的拉起方式;

SpringBootServletInitializer是部署在Web容器(如Tomcat)里面使用Servlet3.0机制拉起的方式,参考

二者互不相干,是为了兼容不同的部署方式。

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文