在上一篇《解读Servlet原理篇一》中提到,要实现javax.servlet.Servlet接口(即写自己的Servlet应用),你可以写一个继承自javax.servlet.GenericServletr的generic Servlet ,也可以写一个继承自java.servlet.http.HttpServlet的HTTP Servlet(这就是为什么我们自定义的Servlet通常是extentds HttpServlet的)。
那GenericServlet和HttpServlet的区别是什么,如何使用这两个类呢?
一:大话GenericServlet
Servlet API中是这样描述GenericServlet的:
Defines a generic, protocol-independent servlet. To write an HTTP servlet for use on the Web, extend HttpServlet instead.GenericServlet implements the Servlet and ServletConfig interfaces. GenericServlet may be directly extended by a servlet, although it's more common to extend a protocol-specific subclass such as HttpServlet.GenericServlet makes writing servlets easier. It provides simple versions of the lifecycle methods init and destroy and of the methods in the ServletConfig interface. GenericServlet also implements the log method, declared in the ServletContext interface.
To write a generic servlet, you need only override the abstract service method.
简译之,GenericServlet定义了一个通用的,无关协议的的Servlet。如果要在Web应用中使用Http进行Servlet通信,请扩展HttpServlet(即继承HttpServlet)。
package javax.servlet; import java.io.IOException; import java.io.Serializable; import java.util.Enumeration; public abstract class GenericServlet implements Servlet, ServletConfig, Serializable { private transient ServletConfig config; public void destroy() { } public String getInitParameter(String name) { return getServletConfig().getInitParameter(name); } public Enumeration getInitParameterNames() { return getServletConfig().getInitParameterNames(); } public ServletConfig getServletConfig() { return this.config; } public ServletContext getServletContext() { return getServletConfig().getServletContext(); } public String getServletInfo() { return ""; } public void init(ServletConfig config) throws ServletException { this.config = config; init(); } public void init() throws ServletException { } public void log(String msg) { getServletContext().log(getServletName() + ": " + msg); } public void log(String message, Throwable t) { getServletContext().log(getServletName() + ": " + message, t); } public abstract void service(ServletRequest paramServletRequest, ServletResponse paramServletResponse) throws ServletException, IOException; public String getServletName() { return this.config.getServletName(); } }
需要注意的点:
- GenericServlet是个抽象类,不能直接进行实例化,必须给出子类才能实例化。即:GenericServlet gs = new GenericServlet(); 编译会报错。GenericServlet gs = new MyServlet(); 这样是正确的(其中MyServlet是其子类)
- 其service()方法是个抽象方法,即它把处理请求的任务交给了子类。子类必须实现该方法。
- 总得来看,它给出了设计servlet的一些骨架,定义了servlet生命周期,还有一些得到名字、配置、初始化参数的方法,其设计的是和应用层协议无关的,也就是说你有可能用非http协议实现它(其实目前Java Servlet还是只有Http一种)。
二:续说HttpServlet
package javax.servlet.http; import java.io.IOException; import java.io.Serializable; import java.lang.reflect.Method; import java.text.MessageFormat; import java.util.Enumeration; import java.util.ResourceBundle; import javax.servlet.GenericServlet; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public abstract class HttpServlet extends GenericServlet implements Serializable { private static final long serialVersionUID = 1L; private static final String METHOD_DELETE = "DELETE"; private static final String METHOD_HEAD = "HEAD"; private static final String METHOD_GET = "GET"; private static final String METHOD_OPTIONS = "OPTIONS"; private static final String METHOD_POST = "POST"; private static final String METHOD_PUT = "PUT"; private static final String METHOD_TRACE = "TRACE"; private static final String HEADER_IFMODSINCE = "If-Modified-Since"; private static final String HEADER_LASTMOD = "Last-Modified"; private static final String LSTRING_FILE = "javax.servlet.http.LocalStrings"; private static ResourceBundle lStrings = ResourceBundle .getBundle("javax.servlet.http.LocalStrings"); protected long getLastModified(HttpServletRequest req) { return -1L; } protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { NoBodyResponse response = new NoBodyResponse(resp); doGet(req, response); response.setContentLength(); } 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(405, msg); else resp.sendError(400, msg); } 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(405, msg); else resp.sendError(400, msg); } protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String protocol = req.getProtocol(); String msg = lStrings.getString("http.method_put_not_supported"); if (protocol.endsWith("1.1")) resp.sendError(405, msg); else resp.sendError(400, msg); } protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String protocol = req.getProtocol(); String msg = lStrings.getString("http.method_delete_not_supported"); if (protocol.endsWith("1.1")) resp.sendError(405, msg); else resp.sendError(400, msg); } private static Method[] getAllDeclaredMethods(Class c) { if (c.equals(HttpServlet.class)) { return null; } Method[] parentMethods = getAllDeclaredMethods(c.getSuperclass()); Method[] thisMethods = c.getDeclaredMethods(); if ((parentMethods != null) && (parentMethods.length > 0)) { Method[] allMethods = new Method[parentMethods.length + thisMethods.length]; System.arraycopy(parentMethods, 0, allMethods, 0, parentMethods.length); System.arraycopy(thisMethods, 0, allMethods, parentMethods.length, thisMethods.length); thisMethods = allMethods; } return thisMethods; } protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Method[] methods = getAllDeclaredMethods(getClass()); boolean ALLOW_GET = false; boolean ALLOW_HEAD = false; boolean ALLOW_POST = false; boolean ALLOW_PUT = false; boolean ALLOW_DELETE = false; boolean ALLOW_TRACE = true; boolean ALLOW_OPTIONS = true; for (int i = 0; i < methods.length; i++) { Method m = methods[i]; if (m.getName().equals("doGet")) { ALLOW_GET = true; ALLOW_HEAD = true; } if (m.getName().equals("doPost")) ALLOW_POST = true; if (m.getName().equals("doPut")) ALLOW_PUT = true; if (m.getName().equals("doDelete")) { ALLOW_DELETE = true; } } String allow = null; if ((ALLOW_GET) && (allow == null)) allow = "GET"; if (ALLOW_HEAD) if (allow == null) allow = "HEAD"; else allow = allow + ", HEAD"; if (ALLOW_POST) if (allow == null) allow = "POST"; else allow = allow + ", POST"; if (ALLOW_PUT) if (allow == null) allow = "PUT"; else allow = allow + ", PUT"; if (ALLOW_DELETE) if (allow == null) allow = "DELETE"; else allow = allow + ", DELETE"; if (ALLOW_TRACE) if (allow == null) allow = "TRACE"; else allow = allow + ", TRACE"; if (ALLOW_OPTIONS) { if (allow == null) allow = "OPTIONS"; else allow = allow + ", OPTIONS"; } resp.setHeader("Allow", allow); } protected void doTrace(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String CRLF = "\r\n"; String responseString = "TRACE " + req.getRequestURI() + " " + req.getProtocol(); Enumeration reqHeaderEnum = req.getHeaderNames(); while (reqHeaderEnum.hasMoreElements()) { String headerName = (String) reqHeaderEnum.nextElement(); responseString = responseString + CRLF + headerName + ": " + req.getHeader(headerName); } responseString = responseString + CRLF; int responseLength = responseString.length(); resp.setContentType("message/http"); resp.setContentLength(responseLength); ServletOutputStream out = resp.getOutputStream(); out.print(responseString); out.close(); } protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String method = req.getMethod(); if (method.equals("GET")) { long lastModified = getLastModified(req); if (lastModified == -1L) { doGet(req, resp); } else { long ifModifiedSince = req.getDateHeader("If-Modified-Since"); if (ifModifiedSince < lastModified / 1000L * 1000L) { maybeSetLastModified(resp, lastModified); doGet(req, resp); } else { resp.setStatus(304); } } } else if (method.equals("HEAD")) { long lastModified = getLastModified(req); maybeSetLastModified(resp, lastModified); doHead(req, resp); } else if (method.equals("POST")) { doPost(req, resp); } else if (method.equals("PUT")) { doPut(req, resp); } else if (method.equals("DELETE")) { doDelete(req, resp); } else if (method.equals("OPTIONS")) { doOptions(req, resp); } else if (method.equals("TRACE")) { doTrace(req, resp); } else { String errMsg = lStrings.getString("http.method_not_implemented"); Object[] errArgs = new Object[1]; errArgs[0] = method; errMsg = MessageFormat.format(errMsg, errArgs); resp.sendError(501, errMsg); } } private void maybeSetLastModified(HttpServletResponse resp, long lastModified) { if (resp.containsHeader("Last-Modified")) return; if (lastModified >= 0L) resp.setDateHeader("Last-Modified", lastModified); } 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); } }
需要注意的点:
- HttpServlet也是个抽象类,不能直接进行实例化,必须给出子类才能实例化(即不能直接使用,只能继承它)。
- HttpServlet是采用Http协议进行通信的,所以它也实现Http协议中的多种方法,每种方法可以处理相应类型的请求
Http协议方法 |
HttpServlet实现方法 |
OPTIONS |
doOption() |
GET |
doGet() |
POST |
doPost() |
TRACE |
doTrace() |
PUT |
doPut() |
DELETE |
doDelete() |
- HttpServlet的service()方法比较特殊,带public关键字的service()方法明显是继承自父类,它只接收HTTP请求,这里把相应的request和response转换为了基于HTTP协议的相应对象,最终将请求转到带protected关键字的service()方法中。protected service()方法根据请求的类型将请求转发到相应的doDelete()、doGet()、doOptions()、doPost()、doPut()等方法中。所以开发自己的Servlet时,不需要覆盖HttpServlet的service()方法,因为该方法最终将请求转发相相应的doXXX方法中,只需要覆盖相应的doXXX方法进行请求处理即可。如果重写了该方法,那么就不会根据方法名调用其他具体的方法了。
- 同上道理, doOptions和doTrace方法也不需要覆盖。
- 查看doGet、doPost、doPut、doDelete四个方法代码,发现这些方法只是判断协议类型,然后抛出相应的异常,其他什么都没做,所以实现自己的Servlet时,需要重写这些方法,以符合自己的需要进行请求处理。
参考资料:
http://www.codejava.net/java-ee/servlet/servlet-api-overview
http://www.uml-diagrams.org/examples/java-servlet-25-api-package-diagram-example.html
https://tomcat.apache.org/tomcat-5.5-doc/servletapi/
https://tomcat.apache.org/tomcat-5.5-doc/servletapi/
http://jzinfo.iteye.com/blog/502581
http://mavforcezt1008.iteye.com/blog/1222966
http://www.itzhai.com/tomcat-source-code-analysis-httpservlet-source-code-analysis.html
相关推荐
6. **Servlet与Filter的协同工作** Filter可以在Servlet处理请求前和响应发送后执行额外操作,例如进行身份验证、日志记录、数据转换等。通过配置`<filter>`和`<filter-mapping>`元素在web.xml中指定Filter的使用。...
核心的接口包括`Servlet`、`GenericServlet`、`HttpServlet`以及`ServletConfig`等。 2. **核心接口** - `Servlet`: 这是所有Servlet的基类,定义了Servlet的基本方法,如`init()`(初始化Servlet)、`service()`...
2. **GenericServlet**:这是一个抽象类,实现了Servlet接口和ServletConfig接口,提供了通用的Servlet功能。开发人员可以通过继承GenericServlet来创建自己的Servlet,只需重写service()方法即可。 3. **...
它包含了一些基本的Servlet和Filter接口,如`Servlet`, `GenericServlet`, `HttpServlet`, `Filter`, `ServletConfig`等。虽然3.1版本提供了更多高级功能,但2.5版本仍被许多老项目和不支持新规范的服务器使用。 3....
虽然通常我们不会直接继承这个类,但会实现`Servlet`接口的子接口`javax.servlet.GenericServlet`或`javax.servlet.http.HttpServlet`。 2. `javax.servlet.ServletConfig`:这个接口提供了Servlet的配置信息,例如...
- **ServletContext**:代表Servlet容器的一个全局信息上下文,可以获取服务器信息,与其他Servlet通信等。 ### 2. JSP(JavaServer Pages) JSP是一种视图技术,它允许开发者将HTML代码与Java代码混合编写,从而...
javax.servlet.GenericServlet javax.servlet.ServletContext javax.servlet.ServletRequest javax.servlet.http.HttpUtils javax.servlet.ServletResponse javax.servlet.ServletException javax.servlet....
1. **Servlet接口**: 这是Servlet API的核心,定义了Web服务器如何与Servlet交互的基本方法,如`init()`, `service()`, `destroy()`。`init()`方法在Servlet被加载时调用,用于初始化Servlet;`service()`方法处理...
Servlet 2.4 API中文版Javadoc文档是一个非常宝贵的资源,尤其对于那些在学习和开发Java Web应用...在阅读和查阅这些文档时,应重点关注每个接口和类的方法、注释和示例,以便更好地掌握Servlet的工作原理和使用方式。
Servlet API的核心接口包括`Servlet`、`GenericServlet`、`HttpServlet`以及`ServletConfig`等。 1. `Servlet`接口:这是所有Servlet的基类,定义了Servlet的基本方法,如`init()`(初始化Servlet)、`service()`...
总之,这个压缩包提供的源码分析对于学习Servlet、GenericServlet和HttpServlet的工作原理极其有价值,能够帮助你深入理解Java Web开发的核心机制,提高你的编程和调试能力。通过细致的阅读和实践,你将能够更加熟练...
- **加载与实例化**:Servlet容器根据web.xml配置文件或者注解找到Servlet类,并加载其类文件,然后创建Servlet实例。 - **初始化**:Servlet容器调用`init()`方法进行初始化,可以在这里设置初始参数或加载配置。...
2. **GenericServlet**:这是一个抽象类,实现了Servlet接口,提供了通用的、与协议无关的Servlet功能。如果你的Servlet需要处理多种协议,可以继承GenericServlet。 3. **HttpServlet**:基于GenericServlet的扩展...
例如,GenericServlet 和 HttpServlet 是Servlet接口的常用抽象基类,提供了基本的HTTP请求处理功能。 2. **ServletConfig接口**:每个Servlet实例都有一个ServletConfig对象,用于传递初始化参数给Servlet。 3. *...
Servlet与JSP的协同工作: - Servlet通常用于处理业务逻辑,而JSP用于展示视图。 - Servlet可以在`doGet()`或`doPost()`中设置请求属性,然后转发到JSP页面。 - JSP通过EL(Expression Language)或JSTL(JavaServer...
本篇文章将深入探讨Servlet的原理,包括其生命周期、执行流程以及如何在实际开发中使用。 首先,我们来了解Servlet的生命周期。Servlet的生命周期分为三个主要阶段:初始化、服务和销毁。在初始化阶段,Servlet容器...
为了简化Servlet的实现,Java提供了一个抽象类`GenericServlet`,它实现了Servlet接口。开发者可以继承`GenericServlet`,然后覆盖`service()`方法,实现处理HTTP请求的逻辑。 3. **HttpServlet类** `HttpServlet...
Servlet API提供了各种接口和类,如`Servlet`, `GenericServlet`, `HttpServlet`, `ServletRequest`, 和 `ServletResponse`,这些都构成了开发Servlet的基础。 `Servlet`接口定义了服务方法(`service()`),该方法...
首先,Servlet容器是Servlet执行的平台,它提供了一套标准接口,使得Servlet与容器之间解耦。以Tomcat为例,它遵循Java Servlet规范,提供了Context、Host、Engine等容器等级,其中Context容器直接管理Servlet的包装...
- 加载与实例化:当服务器接收到对Servlet的首次请求时,会加载Servlet类并创建其实例。 - 初始化:创建实例后,调用`init()`方法进行初始化,通常用来配置Servlet。 - 服务:每当服务器接收到对Servlet的新请求...