minitomcat第十三章:实现生命周期管理(Lifecycle)-MiniTomcat
代长亚功能目标:
- 实现 Lifecycle 组件,用于统一管理各个组件的启动、停止等生命周期操作。
实现内容:
- 定义 Lifecycle 接口,提供
start
和 stop
方法,供容器中的 Context、Wrapper 等组件使用,方便容器统一管理不同组件的生命周期。
背景:
在 Web 容器中,不同的组件(如 Servlet、Web 应用等)通常有明确的生命周期,从创建到销毁需要一系列的管理操作。为了简化对这些组件生命周期的管理,可以引入统一的生命周期管理机制。通过定义 Lifecycle
接口,容器能够统一控制组件的启动、停止,确保资源的正确初始化与销毁。
13.1 生命周期管理的设计思路
我们首先需要定义一个 Lifecycle 接口,所有需要管理生命周期的组件(如 Context
、Wrapper
、Servlet
)都可以实现该接口。该接口定义了两个基本方法:
start()
:表示组件的启动操作。
stop()
:表示组件的停止操作。
这些组件在容器中启动时,将通过调用 start()
方法进行初始化,停止时通过调用 stop()
方法释放资源。
13.2 定义 Lifecycle 接口
首先定义 Lifecycle
接口,它将为实现生命周期管理的组件提供统一的接口。
1 2 3 4 5 6
| package server;
public interface Lifecycle { void start() throws Exception; void stop() throws Exception; }
|
13.3 实现 Context 和 Wrapper 的 Lifecycle 管理
我们将 Context 和 Wrapper 组件实现 Lifecycle 接口,以便统一管理它们的生命周期。
13.3.1 实现 StandardWrapper 类
StandardWrapper
是 Servlet 的封装容器,负责管理单个 Servlet 的生命周期。我们通过实现 Lifecycle
接口,来控制 Servlet 的启动和停止。
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
| package com.daicy.minitomcat.core;
import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
public class StandardWrapper implements Wrapper {
private Servlet servlet;
private String className;
private ServletConfig servletConfig;
public StandardWrapper(ServletConfig servletConfig, String className) { this.servletConfig = servletConfig; this.className = className; }
@Override public void start() throws ServletException { try { servlet = (Servlet) Class.forName(className).newInstance(); servlet.init(servletConfig); } catch (Exception e) { throw new ServletException("Failed to load servlet", e); } }
@Override public void invoke(HttpServletRequest request, HttpServletResponse response) throws Exception { servlet.service(request, response); }
@Override public void stop() { if (servlet != null) { servlet.destroy(); } }
@Override public Servlet getServlet() { return servlet; } }
|
13.3.2 实现 StandardContext 类
StandardContext
是 Web 应用的上下文容器,它管理应用的生命周期,包括加载和卸载多个 Wrapper
。我们同样需要实现 Lifecycle
接口来管理整个 Web 应用的启动和停止。
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
| package com.daicy.minitomcat.core;
import com.daicy.minitomcat.WebXmlServletContainer; import com.google.common.collect.Lists;
import javax.servlet.Servlet; import javax.servlet.ServletConfig; import javax.servlet.ServletException;
import java.util.*; import java.util.stream.Collectors;
public class StandardContext implements Context{
private Map<String, Wrapper> wrapperMap = new HashMap<>();
private WebXmlServletContainer config;
public StandardContext(String configFilePath) throws Exception { config = new WebXmlServletContainer(); config.loadConfig(configFilePath); start(); }
public Wrapper getWrapper(String servletPath) { String servletName = config.getServletName(servletPath); return getWrapperByName(servletName); }
public Wrapper getWrapperByName(String servletName) { return wrapperMap.get(servletName); }
@Override public void start() throws Exception { Map<String, ServletConfig> servletConfigMap = config.getServletConfigMap(); for (String className : servletConfigMap.keySet()) { ServletConfig servletConfig = servletConfigMap.get(className); Wrapper wrapper = new StandardWrapper(servletConfig, className); wrapper.start(); wrapperMap.put(servletConfig.getServletName(), wrapper); } }
@Override public void stop() throws Exception { List<Wrapper> wrappers = getWrappers(); if(null == wrappers){ return ; } for (Wrapper wrapper : wrappers){ wrapper.stop(); } }
@Override public List<Wrapper> getWrappers() { return new ArrayList<>(wrapperMap.values()); }
public List<Servlet> getServlets() { List<Wrapper> wrappers = getWrappers(); if(null == wrappers){ return Lists.newArrayList(); } return wrappers.stream().map(Wrapper::getServlet).collect(Collectors.toList()); }
public List<String> getServletNames() { return config.getServletNames(); } }
|
13.4 示例功能:启动和停止 Web 应用
现在我们可以测试 Lifecycle
接口的功能,通过启动和停止 Web 应用来验证我们实现的生命周期管理。
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
| package com.daicy.minitomcat;
import com.daicy.minitomcat.core.StandardContext; import com.daicy.minitomcat.servlet.CustomHttpSession; import com.daicy.minitomcat.servlet.ServletContextImpl;
import javax.servlet.*; import javax.servlet.http.HttpSessionEvent; import java.util.Enumeration;
public class HttpServer { static final String WEB_ROOT = "webroot";
public static ServletContextImpl servletContext = new ServletContextImpl();
public static StandardContext context;
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 { 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 { System.out.println("Server stopping..."); context.stop(); servletContextListenerManager.notifyContextDestroyed(new ServletContextEvent(servletContext)); SessionManager.removeSession(); } catch (Exception e) { e.printStackTrace(); } }
}
|
在这个示例中,我们创建了一个 Context
实例并向其中添加了多个 Wrapper
,每个 Wrapper
关联一个 Servlet 类。然后调用 context.start()
启动应用,context.stop()
停止应用。
13.5 学习收获
通过实现生命周期管理,我们学到了以下几点:
统一的生命周期管理:通过 Lifecycle
接口,我们实现了一个统一的方式来管理组件的启动和停止。容器可以通过统一接口控制各个组件的生命周期,简化了代码结构。
Web 应用的生命周期:通过 Context
和 Wrapper
类的管理,我们能够模拟 Web 应用和 Servlet 的生命周期,理解 Web 容器如何管理多个 Servlet 的生命周期。
组件化管理:生命周期管理让 Web 容器的各个组件可以独立管理,提升了系统的可扩展性和灵活性。
通过生命周期管理机制,我们为 Web 容器提供了更加清晰、规范的组件管理流程,使得每个组件的生命周期操作更加明确。
项目源代码地址:
https://github.com/daichangya/MiniTomcat/tree/chapter13/mini-tomcat