Servlet之详解
曾经我们在学校里糊里糊涂的听老师说Tomcat是一个Servlet容器。
那么为什么你真正了解过么?
首先我们要明确几个概念性的问题。
J2EE--Java 2 Platform, Enterprise Edition(是一个为大企业主机级的计算类型而设计的Java平台)
J2EE的13种技术规范之一:servlet
Servlet
servlet是用java编写的服务器端程序,主要功能在于交互式地浏览和修改数据,生成动态Web内容。狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。
容 器
java是面向对象的,那么容器就是一个特别的大的对象,一般这个容器里有一个Map类型属性,而这个Map来存放其他小对象,容器通过操纵Map来实现创建,管理,销毁等其他对象的生命周期。
那么Servlet容器顾名思义就是来存放Servlet对象的容器。
Servlet『侠义』
接口
Servlet『广义』
实现类
继承结构
1 public interface Servlet { 2 3 /** 4 * Called by the servlet container to indicate to a servlet that the 5 * servlet is being placed into service. 6 * @param config ServletConfig object containing the servlet's 7 * configuration and initialization parameters 8 */ 9 public void init(ServletConfig config) throws ServletException; 10 11 /** 12 * 13 * Returns a {@link ServletConfig} object, which contains that 14 * initializes this servlet 15 */ 16 public ServletConfig getServletConfig(); 17 18 /** 19 * Called by the servlet container to allow the servlet to respond to 20 * a request. 21 */ 22 public void service(ServletRequest req, ServletResponse res) 23 throws ServletException, IOException; 24 25 /** 26 * Returns information about the servlet, such 27 * as author, version, and copyright. 28 * @return String containing servlet information 29 */ 30 public String getServletInfo(); 31 32 /** 33 * Called by the servlet container to indicate to a servlet that the 34 * servlet is being taken out of service. 35 */ 36 public void destroy(); 37 }
Tomcat作为Servlet的容器,具体他是怎么做的呢?
apache-tomcat-8.5.23/config/web.xml 中默认定义了两种Serlvet:
DefaultServlet extends HttpServlet
JspServlet extends HttpServlet
这也就是为什么说Jsp也是一种servlet。
1 <servlet> 2 <servlet-name>default</servlet-name> 3 <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class> 4 <init-param> 5 <param-name>debug</param-name> 6 <param-value>0</param-value> 7 </init-param> 8 <init-param> 9 <param-name>listings</param-name> 10 <param-value>false</param-value> 11 </init-param> 12 <load-on-startup>1</load-on-startup> 13 </servlet> 14 <servlet> 15 <servlet-name>jsp</servlet-name> 16 <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class> 17 <init-param> 18 <param-name>fork</param-name> 19 <param-value>false</param-value> 20 </init-param> 21 <init-param> 22 <param-name>xpoweredBy</param-name> 23 <param-value>false</param-value> 24 </init-param> 25 <load-on-startup>3</load-on-startup> 26 </servlet>
ServletConfig顾名思义就是保存Servlet配置
具体有Servlet名字,应用本身,初始化的一些参数,和集合
1 public interface ServletConfig { 2 3 /** 4 * @return the name of the servlet instance 5 */ 6 public String getServletName(); 7 8 /** 9 * Returns a reference to the {@link ServletContext} in which the caller is 10 * executing. 11 * @return a {@link ServletContext} object, used by the caller to interact 12 * with its servlet container 13 */ 14 public ServletContext getServletContext(); 15 16 /** 17 * Returns a <code>String</code> containing the value of the named 18 * initialization parameter, or <code>null</code> if the parameter does not 19 * exist. 20 */ 21 public String getInitParameter(String name); 22 23 /** 24 * @return an <code>Enumeration</code> of <code>String</code> objects 25 * containing the names of the servlet's initialization parameters 26 */ 27 public Enumeration<String> getInitParameterNames(); 28 }
GenericServlet作为抽象的默认实现类,在继承了Servlet和ServletConfig的同时,
提供了一个没有参数的init()方法。
提供了2个log的方法,一个提供日志,一个提供异常记录。
1 public abstract class GenericServlet implements Servlet, ServletConfig, 2 java.io.Serializable { 3 4 private static final long serialVersionUID = 1L; 5 6 private transient ServletConfig config; 7 8 public GenericServlet() { 9 // NOOP 10 } 11 12 /** 13 * A convenience method which can be overridden so that there's no need to 14 * call <code>super.init(config)</code>. 15 */ 16 public void init() throws ServletException { 17 // NOOP by default 18 } 19 20 /** 21 * Writes the specified message to a servlet log file, prepended by the 22 * servlet's name. See {@link ServletContext#log(String)}. 23 */ 24 public void log(String msg) { 25 getServletContext().log(getServletName() + ": " + msg); 26 } 27 28 /** 29 * Writes an explanatory message and a stack trace for a given 30 * <code>Throwable</code> exception to the servlet log file, prepended by 31 * the servlet's name. See {@link ServletContext#log(String, Throwable)}. 32 */ 33 public void log(String message, Throwable t) { 34 getServletContext().log(getServletName() + ": " + message, t); 35 } 36 37 }
HttpServlet 作为次级抽象的实现类,是基于Http协议的Servlet父类。
他定义了7种请求方法(GET,POST,PUT,OPTIONS,DELETE,HEAD,TRACE);
实现了Servlet的Service方法,Service方法作为路由,通过获得请求方法来做相应的请求处理(doGET,doPOST等)
1 public abstract class HttpServlet extends GenericServlet { 2 3 private static final long serialVersionUID = 1L; 4 5 private static final String METHOD_DELETE = "DELETE"; 6 private static final String METHOD_HEAD = "HEAD"; 7 private static final String METHOD_GET = "GET"; 8 private static final String METHOD_OPTIONS = "OPTIONS"; 9 private static final String METHOD_POST = "POST"; 10 private static final String METHOD_PUT = "PUT"; 11 private static final String METHOD_TRACE = "TRACE"; 12 13 private static final String HEADER_IFMODSINCE = "If-Modified-Since"; 14 private static final String HEADER_LASTMOD = "Last-Modified"; 15 16 protected void doGet(HttpServletRequest req, HttpServletResponse resp) 17 throws ServletException, IOException 18 { 19 String protocol = req.getProtocol(); 20 String msg = lStrings.getString("http.method_get_not_supported"); 21 if (protocol.endsWith("1.1")) { 22 resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg); 23 } else { 24 resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg); 25 } 26 } 27 28 protected void doPost(HttpServletRequest req, HttpServletResponse resp) 29 throws ServletException, IOException { 30 31 String protocol = req.getProtocol(); 32 String msg = lStrings.getString("http.method_post_not_supported"); 33 if (protocol.endsWith("1.1")) { 34 resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg); 35 } else { 36 resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg); 37 } 38 } 39 40 protected void service(HttpServletRequest req, HttpServletResponse resp) 41 throws ServletException, IOException { 42 43 String method = req.getMethod(); 44 45 if (method.equals(METHOD_GET)) { 46 long lastModified = getLastModified(req); 47 if (lastModified == -1) { 48 // servlet doesn't support if-modified-since, no reason 49 // to go through further expensive logic 50 doGet(req, resp); 51 } else { 52 long ifModifiedSince; 53 try { 54 ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE); 55 } catch (IllegalArgumentException iae) { 56 // Invalid date header - proceed as if none was set 57 ifModifiedSince = -1; 58 } 59 if (ifModifiedSince < (lastModified / 1000 * 1000)) { 60 // If the servlet mod time is later, call doGet() 61 // Round down to the nearest second for a proper compare 62 // A ifModifiedSince of -1 will always be less 63 maybeSetLastModified(resp, lastModified); 64 doGet(req, resp); 65 } else { 66 resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED); 67 } 68 } 69 70 } else if (method.equals(METHOD_HEAD)) { 71 long lastModified = getLastModified(req); 72 maybeSetLastModified(resp, lastModified); 73 doHead(req, resp); 74 75 } else if (method.equals(METHOD_POST)) { 76 doPost(req, resp); 77 78 } else if (method.equals(METHOD_PUT)) { 79 doPut(req, resp); 80 81 } else if (method.equals(METHOD_DELETE)) { 82 doDelete(req, resp); 83 84 } else if (method.equals(METHOD_OPTIONS)) { 85 doOptions(req,resp); 86 87 } else if (method.equals(METHOD_TRACE)) { 88 doTrace(req,resp); 89 90 } else { 91 // 92 // Note that this means NO servlet supports whatever 93 // method was requested, anywhere on this server. 94 // 95 96 String errMsg = lStrings.getString("http.method_not_implemented"); 97 Object[] errArgs = new Object[1]; 98 errArgs[0] = method; 99 errMsg = MessageFormat.format(errMsg, errArgs); 100 101 resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg); 102 } 103 } 104 105 @Override 106 public void service(ServletRequest req, ServletResponse res) 107 throws ServletException, IOException { 108 109 HttpServletRequest request; 110 HttpServletResponse response; 111 112 try { 113 request = (HttpServletRequest) req; 114 response = (HttpServletResponse) res; 115 } catch (ClassCastException e) { 116 throw new ServletException("non-HTTP request or response"); 117 } 118 service(request, response); 119 } 120 }
而SpringMVC中的DispaticServlet就是继承了HttpServlet。
DispaticServlet的具体请看Spring章节介绍。