一、Servlet分析
1.1、Servlet 源码
public abstract interface Servlet { public abstract void init(ServletConfig paramServletConfig) throws ServletException; public abstract ServletConfig getServletConfig(); public abstract void service(ServletRequest paramServletRequest, ServletResponse paramServletResponse) throws ServletException, IOException; public abstract String getServletInfo(); public abstract void destroy(); }
二、GenericServlet分析
2.1、GenericServlet源代码
1 package javax.servlet; 2 3 import java.io.IOException; 4 import java.io.Serializable; 5 import java.util.Enumeration; 6 7 public abstract class GenericServlet implements Servlet, ServletConfig,Serializable { 9 private transient ServletConfig config; 10 11 public void destroy() { 12 } 13 14 public String getInitParameter(String name) { 15 return getServletConfig().getInitParameter(name); 16 } 17 18 public Enumeration getInitParameterNames() { 19 return getServletConfig().getInitParameterNames(); 20 } 21 22 public ServletConfig getServletConfig() { 23 return this.config; 24 } 25 26 public ServletContext getServletContext() { 27 return getServletConfig().getServletContext(); 28 } 29 30 public String getServletInfo() { 31 return ""; 32 } 33 34 public void init(ServletConfig config) throws ServletException { 35 this.config = config; 36 init(); 37 } 38 39 public void init() throws ServletException { 40 } 41 42 public void log(String msg) { 43 getServletContext().log(getServletName() + ": " + msg); 44 } 45 46 public void log(String message, Throwable t) { 47 getServletContext().log(getServletName() + ": " + message, t); 48 } 49 50 public abstract void service(ServletRequest paramServletRequest, 51 ServletResponse paramServletResponse) throws ServletException, 52 IOException; 53 54 public String getServletName() { 55 return this.config.getServletName(); 56 } 57 }
需要注意的点:
- GenericServlet是个抽象类,不能直接进行实例化,必须给出子类才能实例化。即:GenericServlet gs = new GenericServlet(); 编译会报错。GenericServlet gs = new MyServlet(); 这样是正确的(其中MyServlet是其子类)
- 其service()方法是个抽象方法,即它把处理请求的任务交给了子类。子类必须实现该方法。
- 总得来看,它给出了设计servlet的一些骨架,定义了servlet生命周期,还有一些得到名字、配置、初始化参数的方法,其设计的是和应用层协议无关的,也就是说你有可能用非http协议实现它(其实目前Java Servlet还是只有Http一种)。
三、HttpServlet分析
3.1、HttpServlet源代码
1 package javax.servlet.http; 2 3 import java.io.IOException; 4 import java.io.Serializable; 5 import java.lang.reflect.Method; 6 import java.text.MessageFormat; 7 import java.util.Enumeration; 8 import java.util.ResourceBundle; 9 import javax.servlet.GenericServlet; 10 import javax.servlet.ServletException; 11 import javax.servlet.ServletOutputStream; 12 import javax.servlet.ServletRequest; 13 import javax.servlet.ServletResponse; 14 15 public abstract class HttpServlet extends GenericServlet implements Serializable { 17 private static final long serialVersionUID = 1L; 18 private static final String METHOD_DELETE = "DELETE"; 19 private static final String METHOD_HEAD = "HEAD"; 20 private static final String METHOD_GET = "GET"; 21 private static final String METHOD_OPTIONS = "OPTIONS"; 22 private static final String METHOD_POST = "POST"; 23 private static final String METHOD_PUT = "PUT"; 24 private static final String METHOD_TRACE = "TRACE"; 25 private static final String HEADER_IFMODSINCE = "If-Modified-Since"; 26 private static final String HEADER_LASTMOD = "Last-Modified"; 27 private static final String LSTRING_FILE = "javax.servlet.http.LocalStrings"; 28 private static ResourceBundle lStrings = ResourceBundle 29 .getBundle("javax.servlet.http.LocalStrings"); 30 31 protected long getLastModified(HttpServletRequest req) { 32 return -1L; 33 } 34 35 protected void doHead(HttpServletRequest req, HttpServletResponse resp) 36 throws ServletException, IOException { 37 NoBodyResponse response = new NoBodyResponse(resp); 38 doGet(req, response); 39 response.setContentLength(); 40 } 41 42 protected void doPost(HttpServletRequest req, HttpServletResponse resp) 43 throws ServletException, IOException { 44 String protocol = req.getProtocol(); 45 String msg = lStrings.getString("http.method_post_not_supported"); 46 if (protocol.endsWith("1.1")) 47 resp.sendError(405, msg); 48 else 49 resp.sendError(400, msg); 50 } 51 52 protected void doGet(HttpServletRequest req, HttpServletResponse resp) 53 throws ServletException, IOException { 54 String protocol = req.getProtocol(); 55 String msg = lStrings.getString("http.method_get_not_supported"); 56 if (protocol.endsWith("1.1")) 57 resp.sendError(405, msg); 58 else 59 resp.sendError(400, msg); 60 } 61 62 protected void doPut(HttpServletRequest req, HttpServletResponse resp) 63 throws ServletException, IOException { 64 String protocol = req.getProtocol(); 65 String msg = lStrings.getString("http.method_put_not_supported"); 66 if (protocol.endsWith("1.1")) 67 resp.sendError(405, msg); 68 else 69 resp.sendError(400, msg); 70 } 71 72 protected void doDelete(HttpServletRequest req, HttpServletResponse resp) 73 throws ServletException, IOException { 74 String protocol = req.getProtocol(); 75 String msg = lStrings.getString("http.method_delete_not_supported"); 76 if (protocol.endsWith("1.1")) 77 resp.sendError(405, msg); 78 else 79 resp.sendError(400, msg); 80 } 81 82 private static Method[] getAllDeclaredMethods(Class c) { 83 if (c.equals(HttpServlet.class)) { 84 return null; 85 } 86 Method[] parentMethods = getAllDeclaredMethods(c.getSuperclass()); 87 Method[] thisMethods = c.getDeclaredMethods(); 88 89 if ((parentMethods != null) && (parentMethods.length > 0)) { 90 Method[] allMethods = new Method[parentMethods.length 91 + thisMethods.length]; 92 93 System.arraycopy(parentMethods, 0, allMethods, 0, 94 parentMethods.length); 95 96 System.arraycopy(thisMethods, 0, allMethods, parentMethods.length, 97 thisMethods.length); 98 99 thisMethods = allMethods; 100 } 101 return thisMethods; 102 } 103 104 protected void doOptions(HttpServletRequest req, HttpServletResponse resp) 105 throws ServletException, IOException { 106 Method[] methods = getAllDeclaredMethods(getClass()); 107 108 boolean ALLOW_GET = false; 109 boolean ALLOW_HEAD = false; 110 boolean ALLOW_POST = false; 111 boolean ALLOW_PUT = false; 112 boolean ALLOW_DELETE = false; 113 boolean ALLOW_TRACE = true; 114 boolean ALLOW_OPTIONS = true; 115 116 for (int i = 0; i < methods.length; i++) { 117 Method m = methods[i]; 118 119 if (m.getName().equals("doGet")) { 120 ALLOW_GET = true; 121 ALLOW_HEAD = true; 122 } 123 if (m.getName().equals("doPost")) 124 ALLOW_POST = true; 125 if (m.getName().equals("doPut")) 126 ALLOW_PUT = true; 127 if (m.getName().equals("doDelete")) { 128 ALLOW_DELETE = true; 129 } 130 } 131 String allow = null; 132 if ((ALLOW_GET) && (allow == null)) 133 allow = "GET"; 134 if (ALLOW_HEAD) 135 if (allow == null) 136 allow = "HEAD"; 137 else 138 allow = allow + ", HEAD"; 139 if (ALLOW_POST) 140 if (allow == null) 141 allow = "POST"; 142 else 143 allow = allow + ", POST"; 144 if (ALLOW_PUT) 145 if (allow == null) 146 allow = "PUT"; 147 else 148 allow = allow + ", PUT"; 149 if (ALLOW_DELETE) 150 if (allow == null) 151 allow = "DELETE"; 152 else 153 allow = allow + ", DELETE"; 154 if (ALLOW_TRACE) 155 if (allow == null) 156 allow = "TRACE"; 157 else 158 allow = allow + ", TRACE"; 159 if (ALLOW_OPTIONS) { 160 if (allow == null) 161 allow = "OPTIONS"; 162 else 163 allow = allow + ", OPTIONS"; 164 } 165 resp.setHeader("Allow", allow); 166 } 167 168 protected void doTrace(HttpServletRequest req, HttpServletResponse resp) 169 throws ServletException, IOException { 170 String CRLF = "\r\n"; 171 String responseString = "TRACE " + req.getRequestURI() + " " 172 + req.getProtocol(); 173 174 Enumeration reqHeaderEnum = req.getHeaderNames(); 175 176 while (reqHeaderEnum.hasMoreElements()) { 177 String headerName = (String) reqHeaderEnum.nextElement(); 178 responseString = responseString + CRLF + headerName + ": " 179 + req.getHeader(headerName); 180 } 181 182 responseString = responseString + CRLF; 183 184 int responseLength = responseString.length(); 185 186 resp.setContentType("message/http"); 187 resp.setContentLength(responseLength); 188 ServletOutputStream out = resp.getOutputStream(); 189 out.print(responseString); 190 out.close(); 191 } 192 193 protected void service(HttpServletRequest req, HttpServletResponse resp) 194 throws ServletException, IOException { 195 String method = req.getMethod(); 196 197 if (method.equals("GET")) { 198 long lastModified = getLastModified(req); 199 if (lastModified == -1L) { 200 doGet(req, resp); 201 } else { 202 long ifModifiedSince = req.getDateHeader("If-Modified-Since"); 203 if (ifModifiedSince < lastModified / 1000L * 1000L) { 204 maybeSetLastModified(resp, lastModified); 205 doGet(req, resp); 206 } else { 207 resp.setStatus(304); 208 } 209 } 210 } else if (method.equals("HEAD")) { 211 long lastModified = getLastModified(req); 212 maybeSetLastModified(resp, lastModified); 213 doHead(req, resp); 214 } else if (method.equals("POST")) { 215 doPost(req, resp); 216 } else if (method.equals("PUT")) { 217 doPut(req, resp); 218 } else if (method.equals("DELETE")) { 219 doDelete(req, resp); 220 } else if (method.equals("OPTIONS")) { 221 doOptions(req, resp); 222 } else if (method.equals("TRACE")) { 223 doTrace(req, resp); 224 } else { 225 String errMsg = lStrings.getString("http.method_not_implemented"); 226 Object[] errArgs = new Object[1]; 227 errArgs[0] = method; 228 errMsg = MessageFormat.format(errMsg, errArgs); 229 230 resp.sendError(501, errMsg); 231 } 232 } 233 234 private void maybeSetLastModified(HttpServletResponse resp, 235 long lastModified) { 236 if (resp.containsHeader("Last-Modified")) 237 return; 238 if (lastModified >= 0L) 239 resp.setDateHeader("Last-Modified", lastModified); 240 } 241 242 public void service(ServletRequest req, ServletResponse res) 243 throws ServletException, IOException { 244 HttpServletRequest request; 245 HttpServletResponse response; 246 try { 247 request = (HttpServletRequest) req; 248 response = (HttpServletResponse) res; 249 } catch (ClassCastException e) { 250 throw new ServletException("non-HTTP request or response"); 251 } 252 service(request, response); 253 } 254 }
需要注意的点:
- 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时,需要重写这些方法,以符合自己的需要进行请求处理。
四、三者比较
4.1 servlet 主要类之间的关系
GenericServlet是所有Servlet类的祖先类,实现了接口:Servlet , ServletConfig ,GenericServlet是个抽象的父类,必须给出子类才能实例化
HttpServlet 类继承了GenericServlet
Servlet有两个非常重要的对象,可以说是Java web非常核心的两个对象,HttpServletRequest和HttpServletResponse
4.2 HttpServletRequest和HttpServletResponse 对象
时间: 2024-11-06 07:18:49