玩转 Spring Boot 原理篇(内嵌Tomcat实现原理&优雅停机源码剖析)

SpringBoot源码解读与原理分析(二十七)嵌入式Tomcat 当Web应用需要部署运行时,传统的做法是将项目打包成war包,然后部署到外置的Web容器中(如最常用的Tomcat容器)。SpringBoot的一大重要特性是支持嵌入式Web容器,基于SpringBoot的Web应用仅凭一个单独的jar包即可独立运行。嵌入式Tomcat是一种可以嵌入到Web应用中,无需单独部署的Tomcat容器。普通的外置Tomcat与嵌入式Tomcat从核心、本质上看没有任何区别,都可以承载Web应用的运行。但SpringBoot整合嵌入式Tomcat容器时在底层设定了一些额外的限制。 阅读详情

0. 

4c1dd5882c547dc92a6c1540710a4454.png

0.0. 历史文章整理

玩转 Spring Boot 入门篇

玩转 Spring Boot 集成篇(MySQL、Druid、HikariCP)

玩转 Spring Boot 集成篇(MyBatis、JPA、事务支持)

玩转 Spring Boot 集成篇(Redis)

玩转 Spring Boot 集成篇(Actuator、Spring Boot Admin)

玩转 Spring Boot 集成篇(RabbitMQ)

玩转 Spring Boot 集成篇(@Scheduled、静态、动态定时任务)

玩转 Spring Boot 集成篇(任务动态管理代码篇)

玩转 Spring Boot 集成篇(定时任务框架Quartz)

玩转 Spring Boot 原理篇(源码环境搭建)

玩转 Spring Boot 原理篇(核心注解知多少)

玩转 Spring Boot 原理篇(自动装配前凑之自定义Starter)

玩转 Spring Boot 原理篇(自动装配源码剖析)

玩转 Spring Boot 原理篇(启动机制源码剖析)

0.1. 好奇心害死猫

基于 Spring Boot 搭建 WEB 项目时,只需引入 spring-boot-starter-web 依赖,启动应用时便可以启动 Tomcat 对外提供 WEB 服务,如此之简单,倒是勾起了一探究竟的好奇心。

a0208658051492cf920188b15f96cc12.png

如上图示意,通过 Maven 依赖关系,能够清晰看出,在引入 spring-boot-starter-web 依赖时,默认会自动引入 spring-boot-starter-tomcat 以及 spring-boot-starter 依赖包。

看到 maven 依赖关系,仍不足解决心中疑惑,有待继续撸码来解决心中的疑惑。

  • Spring Boot 如何实现的内嵌 Tomcat?

  • Spring Boot 如何启动内嵌的 Tomcat?

  • Spring Boot 如何停止内嵌的 Tomcat?

开往 Spring Boot 心脏的高铁即将发车,请大家扶稳坐好。

1. 内嵌 Tomcat 实现原理-源码剖析

在 Spring Boot 启动流程里,有 refreshContext(context) 这么一步,这一步会加载 META-INF/spring.factories 文件中配置的一系列的 XxxAutoConfiguration 类,进而来完成自动装配的动作,而 Spring Boot 内嵌 Tomcat 亦是从自动装配开始的。

  • ServletWebServerFactoryAutoConfiguration

@Configuration(proxyBeanMethods = false)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {
// ... ...
}
public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {
// ... ...
}

从源码可以了解到导入了 EmbeddedTomcat,EmbeddedJetty,EmbeddedUndertow 服务器的支持,在用户不指定的情况下,默认情况下使用的是 Tomcat。

97d657469d0e455ecfd1170b4e96d54f.png

当自动装配功能完成之后会接着执行 ServletWebServerApplicationContext 的 onRefresh 的方法,初始化特定上下文子类中的其它特殊的 Bean。

  • AbstractApplicationContext#onRefresh

在 onRefresh 中会调用 createWebServer 创建 Web 服务,在创建 web 服务时,会调用 getWebServerFactory 获得 ServletWebServerFactory,默认创建的是 Tomcat Web服务。

@Override
protected void onRefresh() {
   super.onRefresh();
   try {
      logger.info("【ServletWebServerApplicationContext】【onRefresh】-【开始创建 WEB 服务】");
      // 开始创建 WEB 服务
      createWebServer();
      logger.info("【ServletWebServerApplicationContext】【onRefresh】-【方法执行完毕,创建 WEB 服务完成】");
   }
   catch (Throwable ex) {
      throw new ApplicationContextException("Unable to start web server", ex);
   }
}


// 创建 WEB 服务
 private void createWebServer() {
  WebServer webServer = this.webServer;
  ServletContext servletContext = getServletContext();
  if (webServer == null && servletContext == null) {
   ServletWebServerFactory factory = getWebServerFactory();
   // 重点在这里,主要看这个方法的内部
   this.webServer = factory.getWebServer(getSelfInitializer());
  }
  else if (servletContext != null) {
   try {
    getSelfInitializer().onStartup(servletContext);
   }
   catch (ServletException ex) {
    throw new ApplicationContextException("Cannot initialize servlet context", ex);
   }
  }
  initPropertySources();
 }

其中 ServletWebServerFactory 接口主要有 JettyServletWebServerFactory、UndertowServletWebServerFactory、TomcatServletWebServerFactory 实现。

b89ba005207122b035d09ae3efe5b235.png

接下来仔细瞅瞅 TomcatServletWebServerFactory 对于 getWebServer 方法的实现。

  • TomcatServletWebServerFactory#getWebServer

// Tomcat 对象的初始化
@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {
   if (this.disableMBeanRegistry) {
      Registry.disableRegistry();
   }
   // 完成 Tomcat 的 API 调用
   Tomcat tomcat = new Tomcat();
   File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
   tomcat.setBaseDir(baseDir.getAbsolutePath());
   for (LifecycleListener listener : this.serverLifecycleListeners) {
      tomcat.getServer().addLifecycleListener(listener);
   }
   Connector connector = new Connector(this.protocol);
   connector.setThrowOnFailure(true);
   tomcat.getService().addConnector(connector);
   customizeConnector(connector);
   tomcat.setConnector(connector);
   tomcat.getHost().setAutoDeploy(false);
   configureEngine(tomcat.getEngine());
   for (Connector additionalConnector : this.additionalTomcatConnectors) {
      tomcat.getService().addConnector(additionalConnector);
   }
   // 准备 TomcatEmbeddedContext 并设置到 Tomcat 中
   prepareContext(tomcat.getHost(), initializers);
   // 构建 TomcatWebServer
   return getTomcatWebServer(tomcat);
}


// 获取 Tomcat 服务
protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
   return new TomcatWebServer(tomcat, getPort() >= 0, getShutdown());
}


public TomcatWebServer(Tomcat tomcat, boolean autoStart, Shutdown shutdown) {
   Assert.notNull(tomcat, "Tomcat Server must not be null");
   this.tomcat = tomcat;
   this.autoStart = autoStart;
   this.gracefulShutdown = (shutdown == Shutdown.GRACEFUL) ? new GracefulShutdown(tomcat) : null;
   // 调用  TomcatWebServer#initialize 方法
   initialize();
}


// 完成 Tomcat 的初始化
private void initialize() throws WebServerException {
   logger.info("Tomcat initialized with port(s): " + getPortsDescription(false));
   synchronized (this.monitor) {
      try {
         addInstanceIdToEngineName();


         Context context = findContext();
         context.addLifecycleListener((event) -> {
            if (context.equals(event.getSource()) && Lifecycle.START_EVENT.equals(event.getType())) {
               // Remove service connectors so that protocol binding doesn't
               // happen when the service is started.
               removeServiceConnectors();
            }
         });


         // Start the server to trigger initialization listeners
         //启动服务触发初始化监听器
         this.tomcat.start();


         // We can re-throw failure exception directly in the main thread
         rethrowDeferredStartupExceptions();


         try {
            ContextBindings.bindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());
         }
         catch (NamingException ex) {
            // Naming is not enabled. Continue
         }


         // Unlike Jetty, all Tomcat threads are daemon threads. We create a
         // blocking non-daemon to stop immediate shutdown
         // Tomcat 的线程都是守护线程,我们创建一个阻塞非守护线程来避免立即关闭
         startDaemonAwaitThread();
      }
      catch (Exception ex) {
         stopSilently();
         destroySilently();
         throw new WebServerException("Unable to start embedded Tomcat", ex);
      }
   }
}

在 getWebServer 方法中会完成内嵌 Tomcat API 的调用以及 TomcatServer 的构建,并完成初始化操作,此时控制台打印如下。

c597cc143b242d43a63cbdfc94faf256.png

至此就完成了内嵌 Tomcat 操作,接下来看看内嵌的 Tomcat 如何启动?

2. 内嵌 Tomcat 如何启动-源码剖析


在 finishRefresh() 方法中完成了上下文生命周期处理器的初始化、bean 的启动、并发布上下文刷新的事件。

protected void finishRefresh() {
   // Clear context-level resource caches (such as ASM metadata from scanning).
   clearResourceCaches();
 
   // Initialize lifecycle processor for this context.
   // 为此上下文初始化 lifecycle processor。
   initLifecycleProcessor();
 
   // Propagate refresh to lifecycle processor first.
   getLifecycleProcessor().onRefresh();
 
   // Publish the final event.
   publishEvent(new ContextRefreshedEvent(this));
 
   // Participate in LiveBeansView MBean, if active.
   if (!NativeDetector.inNativeImage()) {
      LiveBeansView.registerApplicationContext(this);
   }
}
  • initLifecycleProcessor()

6d162dd491e67121cef3163c0590a473.png

  • getLifecycleProcessor().onRefresh()

调用 DefaultLifecycleProcessor 的 onRefresh() 方法。

@Override
public void onRefresh() {
   startBeans(true);
   this.running = true;
}
  • DefaultLifecycleProcessor#startBeans()

86b93d669ee0bfc64a5c36c654ce2e47.png

  • DefaultLifecycleProcessor#start()

46210558b31f1184c0daf6930b6ef826.png

  • DefaultLifecycleProcessor#doStart()

0ca6e5736b1e2d15b3ea934e20e23da3.png

  • WebServerStartStopLifecycle#start()

acd177cdd5b6fd1e2a794509d76608dc.png

  • TomcatWebServer#start()

340c1929eedb35dd1f9095fb2391c3f6.png

至此,Spring Boot 内嵌的 Tomcat 就启动成功了。

3. 内嵌 Tomcat 如何关闭(优雅停机)-源码分析

3.1. 发送关闭服务信号

当应用启动完成后,进行 kill 操作,观察程序后续的运行情况。

cc344c6a8cf4571cb1df1ff930baca6f.png

当接收到终止信号时,经过一连串的调用,最终会调用到 AbstractApplicationContext#doClose 方法。

  • AbstractApplicationContext#doClose()

51bfb8286494da026419731f8586e7b1.png

如源码所示,会发布 shutdown 事件,紧接着调用 DefaultLifecycleProcessor#onClose 方法来停止所有的 Lifecycle Bean,例如 WebServerGracefulShutdownLifecycle、WebServerStartStopLifecycle。

  • DefaultLifecycleProcessor#onClose

8c8acb18c4fb717ed0663c74d331f214.png

从 spring.factories 读取 SpringApplicationRunListener 类实例名称,只有 EventPublishingRunListener 一个配置,所以调用 SpringApplicationRunListener 的方法,本质上调用的是 EventPublishingRunListener 这个实现类的方法。

  • DefaultLifecycleProcessor#stopBeans

71e69f6e8dd5d26b043bad130d73ef70.png

  • DefaultLifecycleProcessor#stop()

ecf48d53aeaf5aec2968c9b30c305a19.png

  • DefaultLifecycleProcessor#doStop()

02e8250ec997082443099b1001bc2c59.png

  • WebServerGracefulShutdownLifecycle#stop()

5f634f3350e352e9759d2d6c32bc6fb5.png

  • TomcatWebServer#shutDownGracefully()

4dac480f6e49301d09c16b8469f27743.png

默认没有开启优雅停机,如果在配置中开启优雅停机,则走的是优雅停机分支。

## 开启优雅停机, 如果不配置是默认IMMEDIATE, 立即停机
server.shutdown=graceful
## 优雅停机宽限期时间
spring.lifecycle.timeout-per-shutdown-phase=20s

优雅停机的分支。

e66a9b645db1a4727d5f7d7429e7eaf1.png

当开启优雅停机时,控制台输出如下,会等待所有请求完成,然后进行 shutdown。

356e8fc8274a2a0bf876098eb598c68e.png

当优雅停机的处理完毕后,接着会处理 WebServerStartStopLifecycle 的 stop 操作。

c371aa4703aa0468d55ccdca7644d847.png

  • DefaultLifecycleProcessor#stop

ac53df25d848c35a3e9bf3611b6aeb3d.png

  • DefaultLifecycleProcessor#doStop

5960ec2129aee0be27b4e3db6d2ee88b.png

  • SmartLifecycle#stop

b2d5e37d1a578d18718b90c5ffb61bca.png

  • WebServerStartStopLifecycle#stop

f4f91b9f15c3e352154f9b6748d4c6af.png

  • TomcatWebServer#stop()

17ac920ad4a8328b550ef7e2c015dbe2.png

  • TomcatWebServer#stopTomcat

e1653d9e30c37288f98143ab7f60c47e.png

最终会调用 Tomcat API 完成服务的停止,此时控制台输出如下。

TomcatWebServer stop() ----
INFO 60456 --- [ionShutdownHook] s.tomcat.SampleTomcatApplication         : ServletContext destroyed
Disconnected from the target VM, address: '127.0.0.1:50735', transport: 'socket'
Process finished with exit code 130 (interrupted by signal 2: SIGINT)

4. 例行回顾

本文采取 Debug 的方式跟了一下 Spring Boot 源码,梳理了一下 Spring Boot 内嵌 Tomcat 的主线脉略,并对内嵌 Tomcat 启动、关闭进行了深入了解。

其实回头瞅瞅,Spring Boot 内嵌的 Tomcat 启动、关闭的实现方式,大体可以简化成下面的类图。

  • 内嵌容器启动或关闭时,经过 DefaultLifecycleProcessor 调用一系列方法进行最终是由 WebServerStartStopLifecycle、 WebServerGracefulShutdownLifecycle 来处理。

d03d35e9211425e247540f24da9913e2.png

  • 而WebServerStartStopLifecycle、 WebServerGracefulShutdownLifecycle 持有 webServer 对象,最后调用持有的 X

    xxWebServer 对象的 start、stop 等方法来完成容器的启停操作。

6a88d3bada8e2c6e578735d0c963810d.png

本次就分享到这里,这种内嵌 Tomcat 的实现方式,对于轮子的开发或许有点帮助,你们 get 到了没?

世上没有轻而易举就能获得的成功。所有出众的背后,都有着超乎寻常的努力。真正能够登顶远眺的,都是那些心无旁骛、坚持着往前走的人。再坚持一下,也许你离成功就差那一步。

一起聊技术、谈业务、喷架构,少走弯路,不踩大坑,会持续输出更多精彩分享,欢迎关注,敬请期待!

37f934366f96514b099c84e14ba1aef6.jpeg

参考资料:

https://spring.io/

https://start.spring.io/

https://spring.io/projects/spring-boot

https://github.com/spring-projects/spring-boot

https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/

https://stackoverflow.com/questions/tagged/spring-boot

《Spring Boot实战》《深入浅出Spring Boot 2.x》

《一步一步学Spring Boot:微服务项目实战(第二版)》

《Spring Boot揭秘:快速构建微服务体系》

置顶必读(1) |《滚雪球学 Spring Boot 4.x》专栏目录导航篇(持续更新中)! 🏆 本文收录于 《滚雪球学 Spring Boot 4.x》 专栏。 本专栏面向 有一点 Java 基础,但没有系统学过 Spring Boot 的读者,采用“滚雪球式学习法”:先跑通、再理解、再重构、再上线,最终带你从第一个 Hello API 一路完成一个可部署、可监控、可扩展的后端项目。 阅读详情

相关推荐

告别WSL!实测AMD ROCm7预览版在Windows下跑ComfyUI,速度提升与避坑全记录

本文详细记录了在Windows原生环境下部署AMD ROCm7+PyTorch+ComfyUI的全流程,相比WSL环境性能显著提升。涵盖硬件兼容性确认、开发环境配置、Python环境搭建、ComfyUI部署优化及性能对比测试,为AI绘图爱好者提供实用指南。

weixin_42528090的博客 671

springboot3.0.6官方文档阅读系列:如何优雅的shutdown【graceful shutdown】

停止进程会有一个超时时间,在这段时间内已经存在的请求将会被允许完成,但是新请求是不允许的。新请求不被允许的确切方式取决于web server的用法。通常我们使用kill -9 pid来结束java进程,但是想要graceful shutdown应用时,就不能再暴力的使用kill -9来结束进程了,除了在配置文件中打开配置还需要使用kill -2 pid来给应用发送中断信号。如果你的IDE没有发送正确的SIGTERM信号,graceful shutdown可能没法正常使用,请参考IDE文档了解更多详细信息。

gairuichan的博客 1384

Keil5安装多版本共存方案:实用技巧分享

分享Keil5安装过程中实现多版本共存的实用方法,解决开发环境冲突问题。通过合理配置路径与版本管理,让keil5安装更高效稳定,提升嵌入式开发体验。

weixin_42514750的博客 1530

Spring Boot 2.3 新特性 优雅退出

在最新版的Spring Boot 2.3中终于集成了优雅退出(Graceful shutdown),在官方文档中可以看到内置的 web 服务器(Jetty、Reactor Netty、T...

勿忘初心 4196

matlab 三维绘图 抛光,瓷砖抛光过程建模与仿真

:瓷砖抛 光过程 建模与仿真朱 成 就(广 东工业大学 机 电工程 学院, 广东广州 )摘要 :瓷砖的抛磨影响 因素众 多 ,实际磨削加工时容易出现漏抛 、返抛现象 。对陶瓷抛光机磨头进行运动学分析 ,并基于不 同粒度号 的磨 粒在一定压力下的加工深度模型 ,探讨抛光机磨 头转 速 、横梁摆动频率 、传送速度对瓷砖抛光加工表 面均匀性 的影响,然 后结合 磨削机理使 用 对陶瓷抛光过程进行仿真 ...

weixin_36331058的博客 747

基于Simulink的无线充电系统LCC补偿网络建模与控制

本文详细介绍了基于Simulink的无线充电系统LCC补偿网络建模与控制方法。首先分析了LCC补偿网络的恒流输出、软开关实现和抗偏移能力等优势,并对比了不同补偿拓扑特性。随后分步骤讲解了Simulink建模流程,包括LCC主电路构建、关键参数设计、双闭环控制系统实现等核心环节。重点阐述了移相控制策略和软开关验证方法,提供了系统效率计算和抗偏移测试的调试技巧。最后展示了仿真结果,在耦合系数变化20%时,闭环系统仍能保持输出电压稳定在±2%波动范围内。文章还探讨了工程扩展方向,并针对常见问题给出了解决方案,为无

xiaoheshang_123的博客 539

Spring boot 项目中如何优雅停止服务的五种方法,值得收藏!

一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门即可获取!” />[外链图片转存中…(img-GdzewhbS-1712070626836)][外链图片转存中…(img-Hcttz0W5-1712070626836)][外链图片转存中…(img-fchyYDxT-1712070626836)]《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门即可获取!

efgtrrg的博客 2930

YOLO26 正式发布源代码!极致速度优化方案, 面向工业级落地的目标检测模型!

YOLO26 作为 Ultralytics 公司于 2025 年 9 月发布的最新一代目标检测模型,在架构设计和技术实现上展现了显著的创新。本文深入分析了 YOLO26 的核心架构改进和技术原理,重点探讨了其在边界框回归、推理流程、损失函数设计和优化算法方面的突破性进展。

魔改工程师的博客 1243

springboot2.6源码解析--关闭循环依赖原理

默认配置 spring.main.allow-circular-references=false 在此版本中 boot添加一个配置项 默认关闭处理循环依赖 将此配置设置成true则可解决循环依赖 源码位置:org.springframework.boot:spring-boot:2.6.0 下 package org.springframework.boot.SpringApplication 看代码 private void prepareContext(DefaultBootstrapContext

little_crab_的博客 2203

27930-2015+充电协议解析

对2015+充电与2015充电进行硬件电路对比、通信协议对比和2015+通信协议解析。

manjixingkong1234的专栏 235

一篇文章带你搞定数学建模里的主成分分析(05年水质问题示例应用讲解含代码)

文章目录一、题目分析二、原理公式三、MATLAB实现某一地区的主成分分析四、MATLAB 实现所有地区28个月的综合分析五、注意 一、题目分析 对长江近两年多的水质情况做出定量的综合评价,并分析各地区水质的污染状况 考虑到各指标之间可能存在一定的相关性,选用主成分分析法对长江流域主要城市水质检测报告进行分析,选取主成分,并把主成分得分按照方差贡献率加权求和,得到每个地区的污染综合评价指数,进而可以计算每个月长江流域的污染综合评价指数,对平均综合评价指数进行排序 二、原理公式 根据主成分分析的方法,分析长江沿

南淮北安的博客 2625

Spring Cloud Gateway报错:Unable to start embedded Tomcat

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled. 2019-08-05 20:47:09.045 ERROR 10244 --- [ main] o.s.boot.SpringApplication ...

Masli的博客 6580

最新Python爬虫实战(入门爬虫篇)——案例1:某瓣网站Top250图片数据采集(附上完整爬虫代码)

本次案例通过Python爬虫技术实现了某瓣Top250电影封面的批量下载。代码采用模块化设计,函数实现cookies的自动解析,简化了配置流程,涵盖请求、解析、存储的完整流程。学习重点包括:抓包工具定位数据源、正则表达式匹配图片链接、模拟请求头绕过反爬机制、以及自动化文件管理。需要注意控制请求频率并遵守网站使用规范,适用于入门爬虫实践。

努力让自己发光,对的人才能迎着光而来 16万+

SpringBoot 优雅停机演进:实现原理与最佳实践

摘要 本文探讨了Spring Boot应用优雅停机的实现机制。在2.3版本前,开发者需要手动编码控制关闭顺序,存在Web容器与Spring容器关闭不同步的问题。Spring Boot 2.3引入了原生优雅停机支持,通过反转关闭顺序(先暂停Web容器接收请求,等待处理完成后再关闭Spring容器)和标准化WebServer接口,实现了开箱即用的平滑停机功能。文章详细对比了新旧版本的实现差异,并解释了底层通过SmartLifecycle控制关闭阶段的原理。配置简单,只需设置server.shutdown=gra

码到三十五 9万+

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

Spring Boot 内嵌容器 Tomcat / Undertow / Jetty 优雅停机实现

Spring Boot 内嵌容器 Tomcat / Undertow / Jetty 优雅停机实现 ...

WGH100817的博客 171

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

从源码看Spring Boot的关机彩蛋:Shutdown Hook与Tomcat容器的联动机制

本文深入解析Spring Boot优雅停机机制,重点探讨Shutdown Hook与Tomcat容器的协同工作原理。通过源码分析展示Spring Boot如何在微服务架构中实现请求平滑终止、资源安全释放,并提供线程池配置、Kubernetes集成等实践建议,帮助开发者构建高可用系统。

aa123的博客 712

如何优雅关闭 Spring Boot 应用

如何优雅关闭 Spring Boot 应用

one的博客 1813

Racket 仓库内嵌 lz4(1) 命令手册深度解读:压缩、解压、多线程与全部选项实战指南

本篇技术指南以 Racket 仓库中 ChezScheme 子系统内嵌的 lz4 项目 [programs/lz4.1.md](https://link.gitcode.com/i/79a2b7e8e9c3c3d51f1127bd6d02712b) 命令手册为核心骨架,结合同目录下的 CLI 源码、库实现与测试脚本,系统讲解 `lz4` / `unlz4` / `lz4cat` 三个命令的完整用法

gitblog_00188的博客 965

优雅关闭 Spring Boot 应用

前言 随着线上应用逐步采用 SpringBoot 构建,SpringBoot应用实例越来多,当线上某个应用需要升级部署时,常常简单粗暴地使用 kill 命令,这种停止应用的方式会让应用将所有处理中的请求丢弃,响应失败。这样的响应失败尤其是在处理重要业务逻辑时需要极力避免的,那么有什么更好的方式来平滑地关闭 SpringBoot 应用呢?那就通过本文一起来探究吧。(本文主要针对基于Spring B...

gw的博客 277

如何优雅的关闭 Spring Boot 应用?

01 前言 随着线上应用逐步采用 SpringBoot 构建,SpringBoot应用实例越来多,当线上某个应用需要升级部署时,常常简单粗暴地使用 kill 命令,这种停止应用的方式会让应用将所有处理中的请求丢弃,响应失败。这样的响应失败尤其是在处理重要业务逻辑时需要极力避免的,那么有什么更好的方式来平滑地关闭 SpringBoot 应用呢?那就通过本文一起来探究吧。(本文主要针对基于Sprin...

mifffy_java的博客 327

SpringBoot 优雅停服

当外部流量请求到服务端接口执行业务逻辑的时候,若服务端此时执行关机 (kill),spring boot 默认情况会直接关闭容器(tomcat 等),导致此业务逻辑执行失败。在一些业务场景下:会出现数据不一致的情况,事务逻辑不会回滚。

stay hungry ! stay foolish! 1077

如何优雅关闭 Spring Boot 应用(Java 微服务)推荐收藏

随着线上应用逐步采用 SpringBoot 构建,SpringBoot应用实例越来多,当线上某个应用需要升级部署时,常常简单粗暴地使用 kill 命令,这种停止应用的方式会让应用将所有处理中的请求丢弃,响应失败。这样的响应失败尤其是在处理重要业务逻辑时需要极力避免的,那么有什么更好的方式来平滑地关闭 SpringBoot 应用呢?那就通过本文一起来探究吧。(本文主要针对基于Spring Boot ...

Gabriel的专栏 395
上一篇: 玩转 Spring Boot 原理篇(启动机制源码剖析)
下一篇: 玩转 Spring Boot 应用篇(搭建菜菜的店铺)
一猿小讲
博客等级 码龄15年 294粉丝 156原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值