热部署就是在服务器运行时重新部署项目,热加载即在在运行时重新加载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文件能够动态加载 。我们分为以下三步- 正常启动Tomcat 。输入http://localhost:8080/mywebapp/myservlet,观察页面输出
- 在Tomcat启动的情况下修改MyServlet文件后覆盖原来的class文件
- 再次观察页面情况 。观察页面输出是否修改

文章插图
我们可以看到在Tomcat运行的情况下,直接替换class文件是能够直接生效的 。那么Tomcat是如何做到的呢?其实我们可以自己推导一下 。
- 所有的class文件都是交由类加载来管理的
- 如果换了class文件是不是只需要更换相应的类加载器重新加载就行
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();}............省略}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 绿茶和柠檬的功效,柠檬绿茶的做法
- 白毫银针和白牡丹区别,白毫银针十不采
- 白茶的产地和历史,安吉白茶产地环境
- CSS3伪类:valid和:invalid实现表单校验
- 软件是怎样控制硬件的?
- windows10休眠和睡眠的区别-windows的睡眠和休眠的区别-
- 家里就一台电脑,我和儿子都想用,用ASTER软件可以暂时解决
- 比伽马射线暴威力更大的宇宙现象 太阳系中最热的星球
- 外星人真实存在,还和美国达成了协议 专家称美国与外星人有协议
- 《和女民警的浪漫故事》?女民警美篇
