servlet 源码分析
生活随笔
收集整理的這篇文章主要介紹了
servlet 源码分析
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
servlet源碼分析
- 1. servlet接口
- 1.1 看servlet源碼
- 1.2 直接用類實現servlet接口,來寫servlet類
- 2. servlet子類GenericServlet
- 2.1 servlet子類實現GenericServlet抽象類
- 2.2 繼承GenericServelt抽象類
- 3. httpServelt類分析
- 4. 這么多搬來的代碼,最后總結
1. servlet接口
1.1 看servlet源碼
// 接口是一種標準,規范 public interface Servlet {// 初始化servletpublic void init(ServletConfig config) throws ServletException;// service服務方法public void service(ServletRequest req, ServletResponse res)throws ServletException, IOException;// servlet的信息,如作者...public String getServletInfo();// servlet 銷毀public void destroy(); }- 注意,tomcat只認上面的標準,如以ServletRequest請求對象,ServletConfig等…
1.2 直接用類實現servlet接口,來寫servlet類
package com.lovely.servlet;import java.io.IOException;import javax.servlet.Servlet; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse;public class Servlet1 implements Servlet {// 1.寫一個類實現Servlet接口,// 然后當客戶端請求Servlet之后,// servlet拿到自己的名字,打印到客戶端(解決亂碼問題)private ServletConfig config;public void destroy() {}public ServletConfig getServletConfig() {return this.config;}public String getServletInfo() {return null;}public void init(ServletConfig config) throws ServletException {this.config = config;// 初始化時賦值配置信息}public void service(ServletRequest req, ServletResponse resp)throws ServletException, IOException {resp.setContentType("text/html;charset=utf-8");resp.getWriter().print("servlet名字為: " + config.getServletName());// 得到web.xml 配置信息System.out.println(config.getInitParameter("encode"));}}2. servlet子類GenericServlet
- servletconfig接口
2.1 servlet子類實現GenericServlet抽象類
package javax.servlet;import java.io.IOException; import java.util.Enumeration;public abstract class GenericServlet implements Servlet, ServletConfig,java.io.Serializable {private static final long serialVersionUID = 1L;private transient ServletConfig config;public GenericServlet() {}public void destroy() {}// web.xml <param-init/>信息public String getInitParameter(String name) {return getServletConfig().getInitParameter(name);}public Enumeration<String> getInitParameterNames() {return getServletConfig().getInitParameterNames();}// 返回servlet配置信息public ServletConfig getServletConfig() {return config;}// servletContext 也是一個接口public ServletContext getServletContext() {return getServletConfig().getServletContext();}// servlet信息public String getServletInfo() {return "";}// 實現了servlet接口中的init方法。 tomcat可以認識的init 方法public void init(ServletConfig config) throws ServletException {this.config = config;// 調用了下面重載的init方法this.init();}// 重載init方法!!! public void init() throws ServletException {}// 兩個log都是日志信息public void log(String msg) {getServletContext().log(getServletName() + ": " + msg);}public void log(String message, Throwable t) {getServletContext().log(getServletName() + ": " + message, t);}// servlet接口中未實現的service方法public abstract void service(ServletRequest req, ServletResponse res)throws ServletException, IOException;// 重寫得到配置信息public String getServletName() {return config.getServletName();} }2.2 繼承GenericServelt抽象類
// 有適配器的味道了 package com.lovely.servlet;import java.io.IOException;import javax.servlet.GenericServlet; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse;public class MyServlet1 extends GenericServlet {/*** 2.寫一個類繼承GenericServlet,測試servlet的生命周期*/private static final long serialVersionUID = 1L;/*** init() 方法分析* 重寫GenericServlet init(), 但是tomcat不會調用下面手寫的init(), 它不認得 * 就找到init(ServletConfig config),而它里面調用了自身的重載的init() 承上啟下* 而GenericServlet重載的init() 被子類重寫啦* 則:* myservlet1初始化*/ public void init() throws ServletException {System.out.println("myservlet1初始化");}@Overridepublic void service(ServletRequest req, ServletResponse resp)throws ServletException, IOException {System.out.println("服務...");}@Overridepublic void destroy() {System.out.println("銷毀...");}}3. httpServelt類分析
package javax.servlet.http;import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; 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 {private static final long serialVersionUID = 1L;// 下面的常量是數據的提交方式 增刪改查 restful風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(LSTRING_FILE);public HttpServlet() {}// make client do anything belowprotected 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);}}protected long getLastModified(HttpServletRequest req) {return -1;}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(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);} else {resp.sendError(HttpServletResponse.SC_BAD_REQUEST, 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(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);} else {resp.sendError(HttpServletResponse.SC_BAD_REQUEST, 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(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);} else {resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);}}private static Method[] getAllDeclaredMethods(Class<?> c) {if (c.equals(javax.servlet.http.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(this.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=METHOD_GET;if (ALLOW_HEAD)if (allow==null) allow=METHOD_HEAD;else allow += ", " + METHOD_HEAD;if (ALLOW_POST)if (allow==null) allow=METHOD_POST;else allow += ", " + METHOD_POST;if (ALLOW_PUT)if (allow==null) allow=METHOD_PUT;else allow += ", " + METHOD_PUT;if (ALLOW_DELETE)if (allow==null) allow=METHOD_DELETE;else allow += ", " + METHOD_DELETE;if (ALLOW_TRACE)if (allow==null) allow=METHOD_TRACE;else allow += ", " + METHOD_TRACE;if (ALLOW_OPTIONS)if (allow==null) allow=METHOD_OPTIONS;else allow += ", " + METHOD_OPTIONS;resp.setHeader("Allow", allow);}protected void doTrace(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{int responseLength;String CRLF = "\r\n";StringBuilder buffer = new StringBuilder("TRACE ").append(req.getRequestURI()).append(" ").append(req.getProtocol());Enumeration<String> reqHeaderEnum = req.getHeaderNames();while( reqHeaderEnum.hasMoreElements() ) {String headerName = reqHeaderEnum.nextElement();buffer.append(CRLF).append(headerName).append(": ").append(req.getHeader(headerName)); }buffer.append(CRLF);responseLength = buffer.length();resp.setContentType("message/http");resp.setContentLength(responseLength);ServletOutputStream out = resp.getOutputStream();out.print(buffer.toString()); out.close();return;} // 重載service方法, 也是要繼承httpservlet子類重寫的方法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) {doGet(req, resp);} else {long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);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 lessmaybeSetLastModified(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); } else if (method.equals(METHOD_DELETE)) {doDelete(req, resp);} else if (method.equals(METHOD_OPTIONS)) {doOptions(req,resp);} else if (method.equals(METHOD_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(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);}}// 重寫GenericServlet,也是tomcat會調用的方法public void service(ServletRequest req, ServletResponse res)throws ServletException, IOException {HttpServletRequest request;HttpServletResponse response;try {// 轉型Http 遵循http 協議。request = (HttpServletRequest) req;response = (HttpServletResponse) res;} catch (ClassCastException e) {throw new ServletException("non-HTTP request or response");}// 調用自身service(HttpServletRequest req, HttpServletResponse resp)的方法,而自身的方法被子類重寫了// 所以自身判斷get/post等其它方法的提交,被覆蓋啦service(request, response);} }- 問題,為什么寫了service方法,doGet() / doPost() 方法會失效?
答:
tomcat只認識service(ServletRequest req, ServletResponse resp),
它調用自身service(HttpServletRequest req, HttpServletResponse resp)的方法,而自身的方法被子類重寫了。
所以自身判斷get/post等其它方法的提交,被覆蓋啦。
4. 這么多搬來的代碼,最后總結
問題1:這些方法為什么可以被tomcat自動調用? 問題2:為什么這些方法不能亂寫,必須有一個固定寫法? 問題3:為什么doGet/doPost與Service方法不能同時出現?一: 以上這些問題與Servlet的體系(繼承)有關系
HttpServlet 繼承 GenericServlet 實現 Servlet接口
注意:Servlet接口是整個Servlet體系的標準所在,tomcat只認這個標準
二:分析完代碼后,servlet到底該怎么寫?
實現Servlet的三種方式:
總結
以上是生活随笔為你收集整理的servlet 源码分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 学以致用——使用莱斯利矩阵模型预测蠵龟种
- 下一篇: python中加入绝对路径_理解Pyth