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;
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实现
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 实现
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资源,仅通过中断唤醒检查状态
本文来自博客园,作者:skystrivegao,转载请注明原文链接:https://www.cnblogs.com/skystrive/p/18951609
整理不易,如果对您有所帮助 请点赞收藏,谢谢~