minitomcat第十五章:支持配置热加载和自动部署-MiniTomcat
代长亚功能目标:
实现内容:
实现一个 目录监控机制,当检测到应用目录中的变化(如新增应用、修改或删除文件)时,自动加载或卸载应用。
支持 web.xml 文件的重新加载,使得配置更新后能自动生效。
提供一个简单的 文件监控线程,持续检测应用目录中的变化,并在变化发生时触发相关的加载或卸载操作。
15.1 热部署的设计
热部署的关键是动态地检测文件系统的变化,并自动加载或卸载 Web 应用。为此,我们可以借助 Java NIO 提供的 WatchService,实现对应用目录中文件的监控。
15.1.1 设计思路
文件监控:使用 WatchService
监控应用目录中的文件变化。包括新增、修改或删除操作。
自动加载应用:当监控到新的应用目录或文件发生变化时,自动加载或更新应用的 Servlet 和配置。
重新加载配置:当 web.xml
文件发生变化时,重新加载该配置文件,并应用新的路由和初始化参数。
15.1.2 使用 WatchService
实现文件监控
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
| package com.daicy.minitomcat;
import com.daicy.minitomcat.core.StandardContext;
import java.net.URL; import java.nio.file.*;
import static com.daicy.minitomcat.HttpServer.CONF_PATH;
public class HotDeployment {
public void startDeploymentMonitor() { try {
URL url = getClass().getResource(CONF_PATH); Path path = Paths.get(url.getPath()); WatchService watchService = FileSystems.getDefault().newWatchService();
path.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_DELETE);
System.out.println("Monitoring directory for changes: " + path.toString());
while (true) { WatchKey key; try { key = watchService.take(); } catch (InterruptedException e) { System.out.println("Monitoring interrupted"); return; }
for (WatchEvent<?> event : key.pollEvents()) { WatchEvent.Kind<?> kind = event.kind(); Path filePath = (Path) event.context(); System.out.println("Event detected: " + kind + " on file: " + filePath);
if (kind == StandardWatchEventKinds.ENTRY_CREATE) { deployApplication(filePath); } else if (kind == StandardWatchEventKinds.ENTRY_MODIFY) { reloadApplication(filePath); } else if (kind == StandardWatchEventKinds.ENTRY_DELETE) { undeployApplication(filePath); } }
boolean valid = key.reset(); if (!valid) { break; } } } catch (Exception e) { e.printStackTrace(); } }
private void deployApplication(Path filePath) { System.out.println("Deploying new application: " + filePath); }
private void reloadApplication(Path filePath) { System.out.println("Reloading application: " + filePath); try { HttpServer.context = new StandardContext("/conf/web.xml"); HttpServer.context.start(); } catch (Exception e) { e.printStackTrace(); } }
private void undeployApplication(Path filePath) { System.out.println("Undeploying application: " + filePath); } }
|
15.1.3 主要方法解析
startDeploymentMonitor:启动文件监控线程,持续监控应用目录中的变化。
deployApplication:当检测到新应用被创建时,执行部署操作,加载应用。
reloadApplication:当检测到应用被修改时,执行重新加载操作,更新配置或类文件。
undeployApplication:当检测到应用被删除时,执行卸载操作,移除应用及其资源。
15.2 web.xml 文件的重新加载
在热部署过程中,web.xml
文件的更新是非常重要的一部分。我们需要在 web.xml
文件被修改后重新加载它,以使新的配置生效。
15.2.1 实现 web.xml 重新加载
1 2 3 4 5 6 7 8 9 10 11
| private void reloadApplication(Path filePath) { System.out.println("Reloading application: " + filePath); try { HttpServer.context = new StandardContext(WEB_XML); HttpServer.context.start(); } catch (Exception e) { e.printStackTrace(); } }
|
15.2.2 主要方法解析
- reloadApplication:重新加载
web.xml
文件,并解析其中的配置,更新 Servlet 的路由和初始化参数。
15.3 集成文件监控与配置热加载
我们将 HotDeployment 组件和 StandardContext 结合,完成整个热部署过程。
15.3.1 集成示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| package com.daicy.minitomcat;
import com.daicy.minitomcat.core.StandardContext; import com.daicy.minitomcat.servlet.ServletContextImpl;
import javax.servlet.*;
public class HttpServer { static final String WEB_ROOT = "webroot";
public static final String CONF_PATH = "/conf";
public static final String WEB_XML = CONF_PATH+ "/web.xml";
public static ServletContextImpl servletContext = new ServletContextImpl();
public static StandardContext context;
public static HotDeployment hotDeployment = new HotDeployment();
public static FilterManager filterManager = new FilterManager();
private static ServletContextListenerManager servletContextListenerManager = new ServletContextListenerManager();
public static HttpSessionListenerManager sessionListenerManager = new HttpSessionListenerManager();
public static void main(String[] args) throws Exception { Thread daemonThread = new Thread(() -> { hotDeployment.startDeploymentMonitor(); }); daemonThread.setDaemon(true); daemonThread.start();
servletContextListenerManager.addListener(new ServletContextListenerImpl()); sessionListenerManager.addListener(new HttpSessionListenerImpl()); servletContextListenerManager.notifyContextInitialized(new ServletContextEvent(servletContext)); context = new StandardContext(WEB_XML); context.start(); filterManager.addFilter(new LoggingFilter()); HttpConnector connector = new HttpConnector(); connector.start();
Runtime.getRuntime().addShutdownHook(new Thread(HttpServer::stop)); }
public static void stop() { try { LogManager.getLogger().info("Server stopping..."); context.stop(); servletContextListenerManager.notifyContextDestroyed(new ServletContextEvent(servletContext)); SessionManager.removeSession(); } catch (Exception e) { e.printStackTrace(); } }
}
|
15.4 学习收获
通过实现热加载和自动部署机制,我们学习了以下内容:
目录监控和事件处理:我们使用 Java NIO 的 WatchService
实现了对文件系统的实时监控,能够及时响应目录中的变化。
热部署与应用更新:通过监控目录变化,我们实现了在不重启服务器的情况下自动加载、更新或卸载应用。这为现代 Web 容器提供了动态部署的能力。
web.xml 文件的重新加载:我们实现了 web.xml
配置文件的重新加载机制,能够在配置发生变化时自动更新容器的行为。
这些实现使得我们的 Web 容器在开发和生产环境中都具有高度的灵活性和动态扩展能力,可以支持快速迭代和应用的持续部署。
项目源代码地址:
https://github.com/daichangya/MiniTomcat/tree/chapter15/mini-tomcat