点击上方“方志朋”,选择“设为星标”

回复”666“获取新整理的面试文章

作者 | 不学无数的程序员

来源 | https://urlify.cn/Ir6Z7n

热部署就是在服务器运行时重新部署项目,热加载即在在运行时重新加载class,从而升级应用。

通常情况下在开发环境中我们使用的是热加载,因为热加载的实现的方式在Web容器中启动一个后台线程,定期检测相关文件的变化,如果有变化就重新加载类,这个过程不会清空Session。而在生产环境我们一般应用的是热部署,热部署也是在Web应用后台线程定期检测,发现有变化就会重新加载整个Web应用,这种方式更加彻底会清空Session。

热加载

热加载其实我们在开发过程中经常使用,例如我们使用Idea开发时,我们在设置页面可以进行设置,当修改文件时,我们可以选择不重启项目,选择重新加载此文件。而在Tomcat中也能设置,Tomcat默认情况下是不开启热加载的。需要在Tomcat路径下的Context.xml中配置reloadable参数来开启这个功能。

<Context reloadable="true"/>

我们演示一下Tomcat是如何热加载的。在webapp下我们新建了一个项目,里面的Servlet文件如下

public class MyServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {System.out.println("MyServlet 在处理 get()请求...");PrintWriter out = response.getWriter();response.setContentType("text/html;charset=utf-8");out.println("<strong>>My Servlet Version1!</strong><br>");}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {System.out.println("MyServlet 在处理 post()请求...");PrintWriter out = response.getWriter();response.setContentType("text/html;charset=utf-8");out.println("<strong>>My Servlet Version1!</strong><br>");}
}

目录结构如下

-webapp-- mywebapp-- WEB-INF-- web.xml-- classes-- MyServlet.class

为了演示Tomcat运行时能修改class文件能够动态加载。我们分为以下三步

  1. 正常启动Tomcat。输入http://localhost:8080/mywebapp/myservlet,观察页面输出

  2. 在Tomcat启动的情况下修改MyServlet文件后覆盖原来的class文件

  3. 再次观察页面情况。观察页面输出是否修改

下面直接用动态图演示效果,更直观一些。

我们可以看到在Tomcat运行的情况下,直接替换class文件是能够直接生效的。那么Tomcat是如何做到的呢?其实我们可以自己推导一下。

  1. 所有的class文件都是交由类加载来管理的

  2. 如果换了class文件是不是只需要更换相应的类加载器重新加载就行

那么接下来我们来验证我们的结论,看一下在Tomcat中是如何实现热加载的。Tomcat要监听class文件是否变化应该是新起了一个线程来观测。那么看到在Context的启动方法中,看到调用了threadStart的方法。

protected void threadStart() {backgroundProcessorFuture = Container.getService(this).getServer().getUtilityExecutor().scheduleWithFixedDelay(new ContainerBackgroundProcessor(),//要执行的RunnablebackgroundProcessorDelay, //第一次执行延迟多久backgroundProcessorDelay, //之后每次隔多久执行一次TimeUnit.SECONDS); //时间单位}
}

其中在后台开启周期性的任务,使用了Java提供的ScheduledThreadPoolExecutor。除了能周期性执行任务以外还有线程池的功能。上面代码中调用了scheduleWithFixedDelay方法,第一个传入的参数就是要执行的任务。我们接下来看任务类ContainerBackgroundProcessor是如何实现的。

protected class ContainerBackgroundProcessor implements Runnable {@Overridepublic void run() {// 请注意这里传入的参数是 " 宿主类 " 的实例processChildren(ContainerBase.this);}protected void processChildren(Container container) {try {//1. 调用当前容器的 backgroundProcess 方法。container.backgroundProcess();//2. 遍历所有的子容器,递归调用 processChildren,// 这样当前容器的子孙都会被处理Container[] children = container.findChildren();for (int i = 0; i < children.length; i++) {// 这里会判断子容器如果已经启动了后台线程,那么这里就不会启动了if (children[i].getBackgroundProcessorDelay() <= 0) {processChildren(children[i]);}}} catch (Throwable t) { ... }

上面代码中我们可以知道具体的后台监听代码是在backgroundProcess方法中实现的。那么我们看Context容器的backgroundProcess方法是如何实现的。

public void backgroundProcess() {//WebappLoader 周期性的检查 WEB-INF/classes 和 WEB-INF/lib 目录下的类文件Loader loader = getLoader();if (loader != null) {loader.backgroundProcess();}............省略
}

进去loader.backgroundProcess();中我们可以看到

public void backgroundProcess() {//此处判断热加载开关是否开启和监控的文件夹中文件是否有修改if (reloadable && modified()) {try {Thread.currentThread().setContextClassLoader(WebappLoader.class.getClassLoader());if (context != null) {//Context重启context.reload();}} finally {if (context != null && context.getLoader() != null) {Thread.currentThread().setContextClassLoader(context.getLoader().getClassLoader());}}}
}

我们可以发现Tomcat热加载的步骤

  1. 如果发现有文件发生变化,热加载开关开启

  2. 关闭Context容器

  3. 重启Context容器

在这个过程中,最重要的部分其实就是类加载器了。因为一个Context容器对应一个类加载器。所以在销毁Context容器的时候也连带着将其类加载器一并销毁了。Context在重启的过程中也会创建新的类加载器来加载我们新建的文件。

热部署

如果还是不懂热部署是什么的,下面演示一遍应该就明白了。Tomcat在启动的时候会将其目录下webapp中war包解压后然后封装为一个Context供外部访问。那么热部署就是在程序运行时,如果我们修改了War包中的东西。那么Tomcat就会删除之前的War包解压的文件夹,重新解压新的War包。

我们发现上面动图中在Tomcat运行时,我们修改了War包的信息,它就会将原来的删除然后重新生成一份。

我们从上面的动图中其实就看出了热部署和热加载的区别了。热部署是将文件夹删除然后重新解压包。那么热加载是由Context容器负责的。那么热部署又是由哪个容器负责呢?因为一个文件夹对应一个Context。既然文件夹都删除了,那么肯定不是由Context容器负责了。那么应该就是Context的父容器Host来负责。

我们可以看到Host容器并没有实现自己的backgroundProcess方法。那么它是如何监听的呢?既然它没有实现方法,肯定是调用了父类的backgroundProcess方法。我们可以看到在父类的backgroundProcess中

 @Overridepublic void backgroundProcess() {.  ...........省略fireLifecycleEvent(Lifecycle.PERIODIC_EVENT, null);}

可以看到周期事件的监听器。而Host的事件监听器是HostConfig类的lifecycleEvent方法

  @Overridepublic void lifecycleEvent(LifecycleEvent event) {if (event.getType().equals(Lifecycle.PERIODIC_EVENT)) {// 周期事件check();} else if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) {// 开始之前事件beforeStart();} else if (event.getType().equals(Lifecycle.START_EVENT)) { // 开始事件start();} else if (event.getType().equals(Lifecycle.STOP_EVENT)) { // 结束事件stop();}}

我们可以看check方法

protected void check() {if (host.getAutoDeploy()) {// 检查Host下所有已经部署的web应用DeployedApplication[] apps =deployed.values().toArray(new DeployedApplication[0]);for (int i = 0; i < apps.length; i++) {if (!isServiced(apps[i].name))checkResources(apps[i], false);}// 检查Web应用是否有变化if (host.getUndeployOldVersions()) {checkUndeploy();}// 执行部署deployApps();}
}

热部署的步骤其实也可以简化为三步骤

  1. 检查Host管理下的所有web应用

  2. 如果原来的Web应用被删除,就将相应Context容器删除

  3. 如果有新War包放进来,就部署相应的War包

热门内容:

  • 大公司为什么都有API网关?没你想的那么简单!

  • SpringBoot 操作 ElasticSearch 详解(万字长文)

  • MySQL:互联网公司常用分库分表方案汇总

  • 一招搞定GitHub下载加速!

  • Java项目构建基础:统一结果,统一异常,统一日志(好文推荐)

最近面试BAT,整理一份面试资料《Java面试BAT通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。

获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

明天见(。・ω・。

热加载和热部署,没听过?看看 Tomcat 是怎么实现的相关推荐

  1. 死磕Tomcat系列(6)——Tomcat如何做到热加载和热部署的

    死磕Tomcat系列(6)--Tomcat如何做到热加载和热部署的 热部署就是在服务器运行时重新部署项目,热加载即在在运行时重新加载class,从而升级应用. 通常情况下在开发环境中我们使用的是热加载 ...

  2. tomcat热加载、热部署-源码解析

    上文:tomcat线程模型-源码解析 热加载和热部署是什么? 请查看原来的写过的文章:热部署和热加载有什么区别? tomcat热加载和执热部署都是通过后台进程检测项目中的.class和目录是否发生变化 ...

  3. java热加载_java热加载

    应用服务器一般都支持热部署(Hot Deployment),更新代码时把新编译的确类 替换旧的就行,后面的程序就执行新类中的代码.这也是由各种应用服务器的独 有的类加载器层次实现的.那如何在我们的程序 ...

  4. 京东 java 研发岗二面:Tomcat 是如何做到热加载和热部署的?

    前言 热部署就是在服务器运行时重新部署项目,热加载即在在运行时重新加载 class,从而升级应用. 通常情况下在开发环境中我们使用的是热加载,因为热加载的实现的方式在 Web 容器中启动一个后台线程, ...

  5. 热加载和热部署的区别

    1.热部署 1)就是已经运行了项目,更改之后,不需要重新tomcat,但是会清空内存,重新打包,重新解压war包运行可能好处是一个tomcat多个项目,不必因为tomcat停止而停止其他的项目,运用于 ...

  6. SpringBoot热加载实现与类加载浅谈

    SpringBoot热加载实现与类加载浅谈 热部署与热加载: 热部署和热加载都是基于类加载器实现的,热加载是服务器监听class等文件的改变然后对改变的文件进行局部加载,所以不会删除session,也 ...

  7. webpack 热加载原理探索

    前言 在使用 dora 作为本地 server 开发一个 React 组件的时候,默认使用了 hmr 插件.每次修改代码后页面直接更新,不需要手动 F5 ,感觉非常惊艳,这体验一旦用上后再也回不去了. ...

  8. java编写hot_类的热加载(Hot Deployment)的简单例子

    应用服务器一般都支持热部署(Hot Deployment),更新代码时把新编译的确类 替换旧的就行,后面的程序就执行新类中的代码.这也是由各种应用服务器的独 有的类加载器层次实现的.那如何在我们的程序 ...

  9. Spring实现热加载MyBatis 的XML配置文件

    为什么80%的码农都做不了架构师?>>>    package com.myapp.util;import java.io.IOException; import java.lang ...

最新文章

  1. HPUX在oracle10g安装和卸载缩写
  2. 显示lib包_【手把手教你】股市技术分析利器之TA-Lib(一)
  3. ArrayList实现原理
  4. 批量关闭公众号推送_啥?微信又出新功能了?或将提醒用户关闭长期未读公众号推送...
  5. restful规范和APIView
  6. 独家:Havok 发布新的 AI 中间件
  7. 搭建vue-cli脚手架
  8. 版本控制工具——subversion
  9. 【信号与系统】信号频谱和测量之汉明窗
  10. (丝滑版)Python使用Opencv画一个哆啦A梦(动态),并制作成可执行文件.exe
  11. Excel函数、快捷键等
  12. h5移动端开发之禁用微信浏览器字体大小设置
  13. android 生成bks_生成android的bks证书
  14. 全网首发!!C++20新特性全在这一张图里了
  15. 做好PMC管理三大工作,轻松搞定生产计划与物料控制
  16. 【arduino】arduino家族,arduino相关各种开发环境汇总,Mixly米思齐最新python开发环境...
  17. linux nohup 命令用法详解
  18. 在Spring中使用JOTM实现JTA事务管理
  19. IT公司是动物园——程序猿、攻城狮、射鸡师、产品锦鲤、西衣鸥!
  20. Ubuntu18.04 安装CUDA前应注意的显卡、驱动版本信息

热门文章

  1. 关于查询ios的app更新的历史版本记录
  2. react的安装使用
  3. react遇到的各种坑
  4. 通过web sql实现增删查改
  5. Linux之socket套接字编程20160704
  6. Android之控件使用
  7. mysql的binlog太多太大占用了空间的解决办法
  8. 【组队学习】十二月微信图文索引
  9. LeetCode实战:合并K个排序链表
  10. 如何利用遗传算法进行自变量降维(代码部分)