Servlet 原理
自定义的 Servlet 运行流程
url-pattern
——> servlet-name
——> servlet-class
——> servlet.service()
- 浏览器输入 url,先查看是否有对应的 静态资源,如果没有则尝试请求动态资源
- 匹配 servlet 的 url-pattern
- 根据 url-pattern 找到 servlet-name
- 根据 servlet-name 找到 servlet-class
- 找到对应的 servlet,调用 service() 方法进行处理
Servlet 生命周期
Servlet 的生命周期:在一个 http 请求到达服务器,访问 Servlet 容器时,如果已存在 Servlet 服务,则调用 Service 服务。如果没有,则进行实例化,然后执行 init() 方法,然后再调用 Service() 服务,使用其中的 get() 方法或 post() 方法,到进程需要销毁时,调用 destroy() 方法,服务器关闭时自动调用 destroy 方法进行销毁。
总体来说,生命周期如下:
-
加载并实例化
-
init()
-
service()
-
destroy()
Servlet 生命周期 —— 默认懒加载
-
第一次访问创建servlet。创建实例,init() 初始化、service() 处理请求
-
第 234... 次访问 service() 处理请求
-
关闭服务器,销毁 destory()
参考:
Servelt 架构
GenericServlet
采用适配器模式
提供一个抽象类GenericServlet【标准通用的Servlet】,该类作为Servlet接口的适配器,以后编写Servlet类不再直接实现Servlet接口了,继承GenericServlet即可。重点实现service方法。
/**
* Defines a generic, protocol-independent servlet. To write an HTTP servlet for
* use on the Web, extend {@link javax.servlet.http.HttpServlet} instead.
* <p>
* <code>GenericServlet</code> implements the <code>Servlet</code> and
* <code>ServletConfig</code> interfaces. <code>GenericServlet</code> may be
* directly extended by a servlet, although it's more common to extend a
* protocol-specific subclass such as <code>HttpServlet</code>.
* <p>
* <code>GenericServlet</code> makes writing servlets easier. It provides simple
* versions of the lifecycle methods <code>init</code> and <code>destroy</code>
* and of the methods in the <code>ServletConfig</code> interface.
* <code>GenericServlet</code> also implements the <code>log</code> method,
* declared in the <code>ServletContext</code> interface.
* <p>
* To write a generic servlet, you need only override the abstract
* <code>service</code> method.
*/
public abstract class GenericServlet implements Servlet, ServletConfig,
java.io.Serializable {
private static final long serialVersionUID = 1L;
private transient ServletConfig config;
public GenericServlet() {
// NOOP
}
@Override
public void destroy() {
// NOOP by default
}
@Override
public String getInitParameter(String name) {
return getServletConfig().getInitParameter(name);
}
@Override
public Enumeration<String> getInitParameterNames() {
return getServletConfig().getInitParameterNames();
}
@Override
public ServletConfig getServletConfig() {
return config;
}
@Override
public ServletContext getServletContext() {
return getServletConfig().getServletContext();
}
@Override
public String getServletInfo() {
return "";
}
@Override
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
public void init() throws ServletException {
// NOOP by default
}
public void log(String msg) {
getServletContext().log(getServletName() + ": " + msg);
}
public void log(String message, Throwable t) {
getServletContext().log(getServletName() + ": " + message, t);
}
@Override
public abstract void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;
@Override
public String getServletName() {
return config.getServletName();
}
}
参考:https://blog.csdn.net/cheng_feng_xiao_zhan/article/details/98073961
HttpServlet
HttpServlet 重载了 service 方法,并在其中定义了 模板方法
模板方法:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
如果创建 HttpServlet 子类并重写 service(HttpServletRequest req, HttpServletResponse resp)
方法,就失去了 模板方法的意义。
//继承的 service 方法
@Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
HttpServletRequest request;
HttpServletResponse response;
try {
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
} catch (ClassCastException e) {
throw new ServletException("non-HTTP request or response");
}
service(request, response);
}
// 定义的处理逻辑,由此拓展出几种请求发发对应的“模板方法”
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String method = req.getMethod();
if (method.equals(METHOD_GET)) {
long lastModified = getLastModified(req);
if (lastModified == -1) {
// servlet doesn't support if-modified-since, no reason
// to go through further expensive logic
doGet(req, resp);
} else {
long ifModifiedSince;
try {
ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
} catch (IllegalArgumentException iae) {
// Invalid date header - proceed as if none was set
ifModifiedSince = -1;
}
if (ifModifiedSince < (lastModified / 1000 * 1000)) {
// If the servlet mod time is later, call doGet()
// Round down to the nearest second for a proper compare
// A ifModifiedSince of -1 will always be less
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}
} else if (method.equals(METHOD_HEAD)) {
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);
} else if (method.equals(METHOD_POST)) {
doPost(req, resp);
} else if (method.equals(METHOD_PUT)) {
doPut(req, resp);
}
....
}
// get 模板
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_get_not_supported");
if (protocol.endsWith("1.1")) {
resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
} else {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
}
}
// post 模板
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_post_not_supported");
if (protocol.endsWith("1.1")) {
resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
} else {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
}
}
参考:
-
模板方法模式 https://www.runoob.com/design-pattern/template-pattern.html
-
继承 HttpServlet 类—模板方法设计模式 https://blog.csdn.net/u011541946/article/details/89954522
Servlet 特性 —— 单例多线程
- 只创建一次
- 多个客户端同时访问一个 servlet.service()