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接口
package javax.servlet;import java.util.Enumeration;public interface ServletConfig {// servlet的 名字public String getServletName();// application public ServletContext getServletContext();// web.xml 配置信息  <init-param></init-param>/***      <init-param><param-name>encode</param-name><param-value>utf-8</param-value></init-param>*/public String getInitParameter(String name);public Enumeration<String> getInitParameterNames();
}

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的三种方式:

  1. 实现Servlet接口(非常不方便)
  2. 继承GenericServlet抽象类(相对于方式1方便很多,但是还是不够方便)
  3. 继承HttpServlet抽象类(最简便)

servlet 源码分析相关推荐

  1. tomcat源码分析_百战卓越108天tomcat和servlet源码分析

    训练大纲(第105天) 大家如果想快速有效的学习,思想核心是"以建立知识体系为核心",具体方法是"守破离".确保老师课堂上做的操作,反复练习直到熟练. 第209 ...

  2. javaweb_笔记2(Servlet源码分析;request详解;请求域;转发和重定向;WebServlet注解;jsp基础语法,JavaBean。)

    1.HttpServlet源码分析 HttpServlet类是专门为HTTP协议准备的.比GenericServlet更加适合HTTP协议下的开发. HttpServlet在哪个包下? jakarta ...

  3. JavaWeb——Servlet(全网最详细教程包括Servlet源码分析)

    JavaWeb--Servlet Tomcat工作机制动画演示(点击动图可全屏观看) 什么是Servlet Servlet(Server Applet),全称Java Servlet,未有中文译文.是 ...

  4. JavaWeb-Servlet源码分析

    文章目录 JavaWeb-Servlet全面分析 Tomcat工作机制动画演示 什么是Servlet Servlet的工作模式 Servlet API 概览 Servlet 的主要类型 Servlet ...

  5. SpringBoot源码分析之内置Servlet容器

    原文链接:http://fangjian0423.github.io/2017/05/22/springboot-embedded-servlet-container/ SpringBoot内置了Se ...

  6. 从源码分析tomcat如何调用Servlet的初始化

    引言 上一篇博客我们将tomcat源码在本地成功运行了,所以在本篇博客中我们从源码层面分析,tomcat在启动的过程中,是如何初始化servlet容器的.我们平常都是将我们的服务部署到 tomcat中 ...

  7. java servlet是单例吗_SpringMVC中DispatchServlet是单例还是多例(附源码分析)

    一开始我只知道DispatchServlet是在web.xml中配置的,所以想当然的以为是单例,但结果和我预想的是有出入的. 一.servlet规范 因为DispatchServlet也是Servle ...

  8. SpringBoot-web开发(四): SpringMVC的拓展、接管(源码分析)

    [SpringBoot-web系列]前文: SpringBoot-web开发(一): 静态资源的导入(源码分析) SpringBoot-web开发(二): 页面和图标定制(源码分析) SpringBo ...

  9. Solr初始化源码分析-Solr初始化与启动

    用solr做项目已经有一年有余,但都是使用层面,只是利用solr现有机制,修改参数,然后监控调优,从没有对solr进行源码级别的研究.但是,最近手头的一个项目,让我感觉必须把solrn内部原理和扩展机 ...

最新文章

  1. java8多线程运行程序_线程,代码和数据–多线程Java程序实际运行的方式
  2. 笔记本计算机无法开机怎么办,笔记本开机没反应,教您笔记本电脑开不了机怎么处理...
  3. 正则表达式2-测试代码
  4. 华为年底将推多款平板产品:顶配版将搭载5nm麒麟9000
  5. APP提示框设计模板|UI设计师灵感好帮手
  6. .net c#购物车模块分析
  7. 【工具】telnet用法
  8. CSS | 使用 PostCSS 插件让 Web 应用支持暗黑模式
  9. C语言开发FlyBird小游戏,飞翔小鸟小游戏,可以直接运行!
  10. 【论文笔记_自监督知识蒸馏】Refine Myself by Teaching Myself : Feature Refinement via Self-Knowledge Distillation
  11. CSS3入门基础(详解)
  12. windows提权常用系统漏洞与对应的补丁编号
  13. 学习笔记20220513
  14. 计算机科学与技术脑电波,科学“读心术”,当脑电波扫描图遇到人工智能
  15. 工业机器人日常维护保养要点总结
  16. 微信O2O,卡在了“连接一切”的迷信上
  17. redis5.0.5版本搭建集群
  18. 如何重启或重置HomePod或HomePod mini?
  19. Solution: X3100集成显卡宽屏分辨率问题
  20. 浅谈电子信息工程、通信工程、电子科学与技术、信息和电子行业的专业方向和就业前景

热门文章

  1. spring mvc学习(43):处理静态资源
  2. spring学习(12):使用junit4进行单元测试
  3. java学习(176):第一个xml的编写
  4. mongo:(1)nosql简介
  5. java 虚类private 继承_Java经典面试36题和答案
  6. java语言中的 继承_Java语言有关继承的总结
  7. Python 问题--encode、decode及shell中文输出
  8. 简述python是怎么处理异常的-Python异常处理知识点总结
  9. java操作Excel的poi 遍历一个工作簿
  10. Qt的简单介绍,发展和由来