SpringBoot源码解读&JUC学习-8-SpringBoot2.7x启动流程中Tomcat的阻塞轮询机制分析-await/sleep(防止CPU空转)

JUC学习-8-SpringBoot2.7x启动流程中Tomcat的阻塞轮询机制分析-await/sleep

步骤一、启动类

@SpringBootApplication
public class RuoYiApplication {
	public static void main(String[] args) {
		// 这是整个应用的起点
		SpringApplication.run(RuoYiApplication.class, args);
	}
}

步骤二:SpringApplication的初始化

 public ConfigurableApplicationContext run(String... args) {
 // 1. 创建StopWatch用于计时
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
		// 2. 准备引导上下文
		ConfigurableApplicationContext context = null;
		this.configureHeadlessProperty();
		 // 3. 获取SpringApplicationRunListeners并启动
		SpringApplicationRunListeners listeners = this.getRunListeners(args);
		listeners.starting(bootstrapContext, this.mainApplicationClass);

		try {
		 // 4. 准备应用参数
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			// 5. 准备环境
			ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
			this.configureIgnoreBeanInfo(environment);
			  // 6. 打印Banner(就是启动时看到的Spring标志)
			Banner printedBanner = this.printBanner(environment);
			// 7. 创建应用上下文
			context = this.createApplicationContext();
			context.setApplicationStartup(this.applicationStartup);
			// 8. 准备上下文
			this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
			// 9. 刷新上下文(这是最关键的一步)
			this.refreshContext(context);
			// 10. 刷新后的操作
			this.afterRefresh(context, applicationArguments);
			// 11. 计时结束
			stopWatch.stop();
			// 12. 启动完成日志
			if (this.logStartupInfo) {
				(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
			}
			// 13. 发布应用已启动事件
			listeners.started(context);
			// 14. 执行Runner
			this.callRunners(context, applicationArguments);
		} catch (Throwable var10) {
			this.handleRunFailure(context, var10, listeners);
			throw new IllegalStateException(var10);
		}

		try {
		 // 15. 发布应用运行中事件
			listeners.running(context);
			return context;
		} catch (Throwable var9) {
			this.handleRunFailure(context, var9, (SpringApplicationRunListeners)null);
			throw new IllegalStateException(var9);
		}
	}

步骤三、Tomcat服务的创建过程

在refreshContext()阶段,Spring Boot会创建内嵌的Tomcat服务器。具体过程如下:

3.1 检测Servlet环境

Spring Boot通过@ConditionalOnClass检测到存在Servlet相关类后,会激活ServletWebServerFactoryAutoConfiguration
@AutoConfiguration
@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
public class ServletWebServerFactoryAutoConfiguration {
	// 自动配置逻辑
}

3.2、创建Tomcat工厂

通过@Import注解 在ServletWebServerFactoryConfiguration.EmbeddedTomcat.class内部类中创建的tomcat工厂
@EnableConfigurationProperties({ServerProperties.class})
@Import({BeanPostProcessorsRegistrar.class, ServletWebServerFactoryConfiguration.EmbeddedTomcat.class, ServletWebServerFactoryConfiguration.EmbeddedJetty.class, ServletWebServerFactoryConfiguration.EmbeddedUndertow.class})
public class ServletWebServerFactoryAutoConfiguration {
	public ServletWebServerFactoryAutoConfiguration() {
	}

3.3、注入定制器

static class EmbeddedTomcat {
		EmbeddedTomcat() {
		}

		@Bean
		// 创建工厂实例(此时仅是空壳,未创建Tomcat)
		TomcatServletWebServerFactory tomcatServletWebServerFactory(ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers, ObjectProvider<TomcatContextCustomizer> contextCustomizers, ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) {
			TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
			
			// 注入定制器(此时只是注册,尚未执行,仅保存到集合)
			factory.getTomcatConnectorCustomizers().addAll((Collection)connectorCustomizers.orderedStream().collect(Collectors.toList()));
			factory.getTomcatContextCustomizers().addAll((Collection)contextCustomizers.orderedStream().collect(Collectors.toList()));
			factory.getTomcatProtocolHandlerCustomizers().addAll((Collection)protocolHandlerCustomizers.orderedStream().collect(Collectors.toList()));
			return factory;
		}
	}

3.4、将application.yml中的server.*配置应用到工厂

遍历所有WebServerFactoryCustomizer实现类(如TomcatServletWebServerFactoryCustomizer)
调用customize()方法,将application.yml中的server.*配置应用到工厂
public Object postProcessBeforeInitialization(Object bean, String beanName) {
	// 1. 检查是否为WebServerFactory类型(如TomcatServletWebServerFactory)
	if (bean instanceof WebServerFactory) {
		// 2. 获取所有匹配的定制器
		List<WebServerFactoryCustomizer<?>> customizers = getCustomizers();

		// 3. 按顺序执行定制器
		for (WebServerFactoryCustomizer<?> customizer : customizers) {
			customizer.customize((WebServerFactory) bean);
		}
	}
	return bean;
}

步骤四、创建WebServer(触发Tomcat实例化)

4.1、步骤二中提到的刷新上下文(// 9. 刷新上下文(这是最关键的一步)

	private void refreshContext(ConfigurableApplicationContext context) {
		if (this.registerShutdownHook) {
			shutdownHook.registerApplicationContext(context);
		}

		this.refresh(context);

 protected void refresh(ConfigurableApplicationContext applicationContext) {
		applicationContext.refresh();
	}

4.2、ConfigurableApplicationContext 类中的

void refresh() throws BeansException, IllegalStateException;

image

4.3、ServletWebServerApplicationContext 类中的

	public final void refresh() throws BeansException, IllegalStateException {
		try {
		// 点击查看refresh实现
			super.refresh();
		} catch (RuntimeException var3) {
			WebServer webServer = this.webServer;
			if (webServer != null) {
				webServer.stop();
			}

			throw var3;
		}
	}

4.4、AbstractApplicationContext 类中的

public void refresh() throws BeansException, IllegalStateException {
		synchronized(this.startupShutdownMonitor) {
			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
			this.prepareRefresh();
			ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
			this.prepareBeanFactory(beanFactory);

			try {
				this.postProcessBeanFactory(beanFactory);
				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
				this.invokeBeanFactoryPostProcessors(beanFactory);
				this.registerBeanPostProcessors(beanFactory);
				beanPostProcess.end();
				this.initMessageSource();
				this.initApplicationEventMulticaster();
				// 点击查看实现
				this.onRefresh();
				this.registerListeners();
				this.finishBeanFactoryInitialization(beanFactory);
				this.finishRefresh();
			} catch (BeansException var10) {
				if (this.logger.isWarnEnabled()) {
					this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);
				}

				this.destroyBeans();
				this.cancelRefresh(var10);
				throw var10;
			} finally {
				this.resetCommonCaches();
				contextRefresh.end();
			}

		}

4.5、onRefresh()选择 ServletWebServerApplicationContent实现

image


4.6、ServletWebServerApplicationContext 类中的

   protected void onRefresh() {
		super.onRefresh();

		try {
		// 查看createWebServer
			this.createWebServer();
		} catch (Throwable var2) {
			throw new ApplicationContextException("Unable to start web server", var2);
		}
	}

4.7、ServletWebServerApplicationContext 类中的

	private void createWebServer() {
		WebServer webServer = this.webServer;
		ServletContext servletContext = this.getServletContext();
		if (webServer == null && servletContext == null) {
			StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");
			 // ► 1. 创建Tomcat实例(此时内存中才有真实Tomcat对象)
			ServletWebServerFactory factory = this.getWebServerFactory();
			createWebServer.tag("factory", factory.getClass().toString());
			// 2. ► 调用getWebServer(),真正创建Tomcat实例
			this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});
			createWebServer.end();
			this.getBeanFactory().registerSingleton("webServerGracefulShutdown", new WebServerGracefulShutdownLifecycle(this.webServer));
			this.getBeanFactory().registerSingleton("webServerStartStop", new WebServerStartStopLifecycle(this, this.webServer));
		} else if (servletContext != null) {
			try {
				this.getSelfInitializer().onStartup(servletContext);
			} catch (ServletException var5) {
				throw new ApplicationContextException("Cannot initialize servlet context", var5);
			}
		}

		this.initPropertySources();
	}

4.8、getWebServer()方法选择TomcatServletWebServerFactory 实现

image


4.9、TomcatServletWebServerFactory 类中的

public WebServer getWebServer(ServletContextInitializer... initializers) {
		if (this.disableMBeanRegistry) {
			Registry.disableRegistry();
		}
		// ► 1. 创建Tomcat实例(此时内存中才有真实Tomcat对象)
		Tomcat tomcat = new Tomcat();
		 // ► 2. 配置基础目录(临时工作目录)
		File baseDir = this.baseDirectory != null ? this.baseDirectory : this.createTempDir("tomcat");
		tomcat.setBaseDir(baseDir.getAbsolutePath());
		Iterator var4 = this.serverLifecycleListeners.iterator();

		while(var4.hasNext()) {
			LifecycleListener listener = (LifecycleListener)var4.next();
			tomcat.getServer().addLifecycleListener(listener);
		}
		// ► 3. 创建并配置Connector(协议处理器)
		Connector connector = new Connector(this.protocol);
		connector.setThrowOnFailure(true);
		tomcat.getService().addConnector(connector);
		
		this.customizeConnector(connector);
		tomcat.setConnector(connector);
		tomcat.getHost().setAutoDeploy(false);
		this.configureEngine(tomcat.getEngine());
		Iterator var8 = this.additionalTomcatConnectors.iterator();
		// ► 5. 准备Context(Servlet容器配置)
		while(var8.hasNext()) {
			Connector additionalConnector = (Connector)var8.next();
			tomcat.getService().addConnector(additionalConnector);
		}
		// ► 5. 准备Context(Servlet容器配置)
		this.prepareContext(tomcat.getHost(), initializers);
		// ► 6. 创建TomcatWebServer并启动
		return this.getTomcatWebServer(tomcat);
	}

4.10、TomcatServletWebServerFactory 类中的

protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
		return new TomcatWebServer(tomcat, this.getPort() >= 0, this.getShutdown());
	}

4.11、TomcatWebServer 中的

	public TomcatWebServer(Tomcat tomcat, boolean autoStart, Shutdown shutdown) {
		this.monitor = new Object();
		this.serviceConnectors = new HashMap();
		Assert.notNull(tomcat, "Tomcat Server must not be null");
		this.tomcat = tomcat;
		this.autoStart = autoStart;
		this.gracefulShutdown = shutdown == Shutdown.GRACEFUL ? new GracefulShutdown(tomcat) : null;
		this.initialize();
	}

4.12、TomcatWebServer 类中的

 private void initialize() throws WebServerException {
		logger.info("Tomcat initialized with port(s): " + this.getPortsDescription(false));
		// 使用同步块确保线程安全的初始化过程
		synchronized(this.monitor) {
			try {
			// 为Tomcat引擎名称添加实例ID保证唯一性
				this.addInstanceIdToEngineName();
				// 获取当前Web应用的上下文对象
				Context context = this.findContext();
				// 添加上下文生命周期监听器
				context.addLifecycleListener((event) -> {
				// 当上下文启动完成时触发
					if (context.equals(event.getSource()) && "start".equals(event.getType())) {
					// 移除临时服务连接器
						this.removeServiceConnectors();
					}

				});
				// 启动内嵌Tomcat服务器
				this.tomcat.start();
				// 检查并抛出启动过程中延迟处理的异常
				this.rethrowDeferredStartupExceptions();

				try {
				 // 将类加载器绑定到JNDI上下文
					ContextBindings.bindClassLoader(context, context.getNamingToken(), this.getClass().getClassLoader());
				} catch (NamingException var5) {
				// 静默处理JNDI绑定异常
				}
				 // 启动守护线程防止JVM退出
				this.startDaemonAwaitThread();
			} catch (Exception var6) {
				this.stopSilently();
				this.destroySilently();
				throw new WebServerException("Unable to start embedded Tomcat", var6);
			}

		}
	}

4.13、TomcatWebServer 类中的

   private void startDaemonAwaitThread() {
       // 创建新线程实例,线程名格式为"container-数字"(使用原子计数器保证唯一性)
		Thread awaitThread = new Thread("container-" + containerCounter.get()) {
		        // 重写线程执行逻辑
			public void run() {
			// 核心阻塞逻辑:调用Tomcat Server的await()方法监听关闭命令
				TomcatWebServer.this.tomcat.getServer().await();
			}
		};
		// 设置线程上下文类加载器(使用当前类的类加载器)
		awaitThread.setContextClassLoader(this.getClass().getClassLoader());
		//显式设置为非守护线程(确保JVM不会因主线程结束而退出)
		awaitThread.setDaemon(false);
		// 启动线程(实际开始执行run()方法)
		awaitThread.start();
	}

4.14、await部分源码展示

   public void await() {
		if (this.getPortWithOffset() != -2) {
			Thread currentThread = Thread.currentThread();
			if (this.getPortWithOffset() == -1) {
				try {
					this.awaitThread = currentThread;

					while(!this.stopAwait) {
						try {
							Thread.sleep(10000L);
						} catch (InterruptedException var65) {
						}
					}
				} finally {
					this.awaitThread = null;
				}

			} else {
					... ...

五、总结:

在Tomcat的await()方法中,Thread.sleep(10000L)的主要作用是实现‌低功耗的阻塞轮询机制‌,其设计意图和实现原理如下:

‌5.1、核心功能‌

通过10秒间隔的休眠周期性地检查stopAwait标志位状态,避免忙等待导致的CPU空转。当外部触发关闭流程时(如执行stop()方法),该标志位会被修改以终止循环。

5.2、‌技术实现特点

资源优化:相比持续轮询,休眠期间线程会释放CPU资源,仅通过中断唤醒检查状态

posted @ 2025-06-27 14:01  skystrivegao  阅读(23)  评论(0)    收藏  举报