简单记录Servlet3.0标准

背景

近段时间打算梳理一下近一年用到的SpringBoot及部分相关starter,计划从Web入手。要了解Java开发的Web应用必然的从其标准(Servlet)开始。

以下内容基本来源Oracle官网对Servlet3.0的介绍,由于存在个人理解偏差建议读者直接阅读原文。
地址:https://download.oracle.com/otndocs/jcp/servlet-3.0-mrel-full-oth-JSpec
备注:登录Oracle网站即可将内容以PDF的方式下载下来(简书不支持上传PDF文件)

概念

  • Servlet是什么?
    servlet是基于Java实现的Web组件,servlet通过servlet容器实现的请求/响应范式。(运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。)
  • Servlet容器是什么?
    servlet容器是Web服务器或应用程序服务器的一部分,它提供发送请求和响应的网络服务,基于MIME解码请求,并格式化基于MIME的响应。一个servlet容器还包含在servlet的生命周期中管理它们。

组成

  • Servlet
    1. Servlet接口是JavaServletAPI的核心抽象。所有Servlet通过扩展一个实现接口。JavaServletAPI中实现Servlet接口是GenericServlet和HttpServlet。在大多数情况下,开发人员将扩展HttpServlet以实现他们的servlet。
      1.1. 通常在开发基于HTTP的Servlet时,Servlet开发人员只需关注HttpServlet中的doGet和doPost方法
      1.2. JSP页面本质也是Servlet


      屏幕截图 2020-04-12 19.12.14.png
    2. javax.servlet.Servlet接口(生命周期如下:)
      2.1. 由Servlet容器调用,执行init方法初始化Servlet,只会执行一次。
      2.2. 由servlet容器调用,执行service方法响应servlet请求,每次请求执行一次。注意:service方法是并发执行,方法内容需要考虑同步共享内存
      2.3. 由servlet容器调用,执行destroy方法销毁Servelt,只会执行一次。
屏幕截图 2020-04-12 18.41.25.png
  • Request

    1. 将来自客户端请求的所有信息封装为一个Request对象。在HTTP协议中,此信息通过HTTP从客户端传输到服务器(注意:也可以自定义其他协议实现)
    2. javax.servlet.ServletRequest接口
      2.1. 方法getServerName:获取当前请求的域名或IP(www.ddblock.com
      2.2. 方法getServerPort:获取当前请求的端口(80)
      2.3. 方法getRemoteAddr:获取最后一个请求服务端的客户端IP,如果使用nginx反向代理时需要特殊处理一下
      2.4. 方法getRemoterHost:获取最后一个请求服务端的客户端主机名,如果使用nginx反向代理时需要特殊处理一下
      2.5. 方法getProtocol:获取当前请求的协议及其版本(HTTP/1.1)
      2.6. 方法getScheme:获取当前请求的具体协议(https)
      2.7. 方法getCharacterEncoding:获取请求体内容的编码格式
      2.8. 方法getContentLength:获取请求体内容的字节长度
      2.9. 方法getLocale:获取客户端接收的语言类型
      2.10. 方法startAsync:将此请求置于异步模式,调用返回的AsyncContext对象的start执行
      2.11. 方法getDispatcherType:获取分发器类型,其中包含FORWARD、 INCLUDE、REQUEST、ASYNC、ERROR
      2.12. 方法getServletContext:获取上下文信息
      2.13. 方法getAsyncContext:获取异步模式下的上下文
  • ServletContext

    1. 定义一组servlet用来与其通信的方法。例如,要获取文件的MIME类型,分派请求或写入日志文件。每个Java虚拟机的每个“web应用程序”都有一个上下文。
    2. javax.servlet.ServletContext接口
      2.1. 方法getContextPath:获取上下文根路径
      2.2. 方法getResourcePaths:获取指定路径下的下级目录集合
      2.3. 方法getMimeType:获取指定文件的MIME类型。通过文件后缀匹配具体MIME类型,具体可参考MimeTypeMappings.properties文件(org/apache/catalina/startup/MimeTypeMappings.properties)
      2.4. 方法getRequestDispatcher:获取指定路径的请求分发器,请求分发器通过包装任何类型的资源响应给客户端
      2.5. 方法addServlet:用于添加在web.xml、web-fragment.xml配置的Servlet或添加了WebListener注解的Servlet
      2.6. 方法addFilter:用于添加在web.xml、web-fragment.xml配置的Filter或添加了WebFilter注解的Filter
      2.7. 方法addListener:用于添加在web.xml、web-fragment.xml配置的Listener或添加了WebListener注解的ServletContextListener
  • Response

    1. 将响应给客户端的所有信息封装为一个Response对象。在HTTP协议中,此信息从服务器传输到客户端通过HTTP头或请求的消息体。
    2. javax.servlet.ServletResponse接口
      2.1. 方法getCharacterEncoding:获取响应body内容的编码格式
      2.2. 方法getContentType:获取响应body的内容类型。如:text/html; charset=UTF-8
      2.3. 方法setContentLength:填充响应客户端的响应body的字节长度
      2.4. 方法getOutputStream:获取ServletOutputStream对象将响应body写入输出流中。getWriter方法也能实现相同功能,但不能同时使用。
      2.5. 方法getWriter:获取PrintWriter对象将响应body写入输出流中。getOutputStream方法也能实现相同功能,但不能同时使用。
      2.6. 方法setBufferSize:设置临时存储响应内容的缓冲区大小,如果设置比总响应内容小则响应内容会分多次响应给客户端
      2.7. 方法flushBuffer:将临时存储响应内容的数据及headers都发送给客户端
  • Filter

    1. 对资源(servlet或静态内容)的请求与响应执行过滤任务。过滤器在doFilter方法。每个过滤器都可以访问一个FilterConfig对象,从中可以获取其初始化参数,以及对ServletContext的引用,该引用可以用于例如加载过滤任务所需的资源
    2. javax.servlet.Filter接口
      2.1. 由Servlet容器调用,执行init方法初始化Filter,只会执行一次。
      2.2. 由servlet容器调用,执行doFilter方法拦截请求与响应,在过滤器链尾端执行servlet,每次请求执行一次。
      2.3. 由servlet容器调用,执行destroy方法销毁Filter,只会执行一次。
屏幕截图 2020-04-14 22.24.52.png
  • Session
    1. 提供一种在多个页面上标识用户的方法请求或访问网站并存储有关该用户的信息。 servlet容器使用此接口在HTTP客户端和HTTP服务器之间创建会话。会话在指定的时间段内持续存在,并且跨越用户的多个连接或页面请求。一个会话通常对应一个用户,该用户可能会多次访问该站点。服务器可以通过多种方式维护会话,例如使用cookie或重写URL。
    2. javax.servlet.http.HttpSession接口
      2.1. 方法isNew:获取当前请求是否是新的会话
      2.2. 方法getMaxInactiveInterval:返回最大时间间隔(以秒为单位),servlet容器将在客户机访问之间保持此会话打开。在此间隔之后,Servlet容器将使会话无效
      2.3. 方法invalidate:使该会话无效,然后取消绑定与之绑定的任何对象
      2.4. 方法getServletContext:返回此会话所属的ServletContext
      2.5. 方法setAttribute、getAttribute:用来存储与获取同一会话的数据

其它说明

  • 重要注解
    1. @WebServlet:用于定义web应用程序中的Servlet组件
    @WebServlet(name="MyServlet", urlPatterns={"/foo", "/bar"})
    public class SampleUsingAnnotationAttributes extends HttpServlet{
        public void doGet(HttpServletRequest req, HttpServletResponse res) {
        }
    }
    
    1. @WebFilter:定义web应用程序中的过滤器
    @WebFilter("/foo")
    public class MyFilter implements Filter {
        public void doFilter(HttpServletRequest req, HttpServletResponse res) {
        }
    }
    
    1. @WebInitParam:用于指定必须传递给Servlet或Filter。是WebServlet和WebFilter的一个属性
    2. @WebListener:定义对web应用程序上下文各类事件监听的监听器。
    javax.servlet.ServletContextListener
    javax.servlet.ServletContextAttributeListener
    javax.servlet.ServletRequestListener
    javax.servlet.ServletRequestAttributeListener
    javax.servlet.http.HttpSessionListener
    javax.servlet.http.HttpSessionAttributeListener
    
    @WebListener
    public class MyListener implements ServletContextListener{
        public void contextInitialized(ServletContextEvent sce) {
            ServletContext sc = sce.getServletContext();
            sc.addServlet("myServlet", "Sample servlet", "foo.bar.MyServlet", null, -1);
            sc.addServletMapping("myServlet", new String[] {"/urlpattern/*" });
        }
    }
    
  • javax.servlet.ServletContainerInitializer接口(基于代码配置,而不是web.xml
    1. 提供容器初始化的扩展逻辑。容器通过jar查找在容器/应用程序启动时由容器提供的服务API(如下图META-INF/services)。框架提供ServletContainerInitializer的实现必须将一个名为ServletContainerInitializer,根据jar服务API,指向ServletContainerInitializer的实现类。除了ServletContainerInitializer之外,我们还有一个注解handleTypes。实现handleTypes注释ServletContainerInitializer用于表示对可能在handletype或者如果它在类的超级类型。容器使用handleTypes注释来确定何时调用初始值设定项的onStartup方法
    @HandlesTypes(WebApplicationInitializer.class)
    public class SpringServletContainerInitializer implements ServletContainerInitializer {
        @Override
        public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
            throws ServletException {
        }
    }
    

屏幕截图 2020-04-15 23.19.56.png

2. spring-boot启动web容器时未按照Servlet3.0规范实现,具体可参考(https://blog.csdn.net/weixin_34128501/article/details/92424885),其实现类为org.springframework.boot.web.embedded.tomcat.TomcatStarter

屏幕截图 2020-04-15 23.30.42.png
  • javax.servlet.RequestDispatcher接口

    1. 表示从客户端接收请求并将请求发送到服务器上的任何资源(例如servlet,HTML文件或JSP文件)的类。 包含forward与include两种模式。
    2. forward模式:将请求从Servlet转发到服务器上的另一个资源(Servlet,JSP文件或HTML文件)。这种方法允许一个Servlet对请求进行初步处理,而另一种资源可以生成响应。
    3. include模式:请求服务器的另外一个资源并将资源作为本Servlet输出的子内容
  • 事件通知

    1. 事件覆盖了ServletContext、HttpSession与ServletRequest的生命周期中。
    2. 具体事件监听器(混个眼熟)


      屏幕截图 2020-04-22 23.12.26.png
      屏幕截图 2020-04-22 23.12.13.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,752评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,100评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,244评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,099评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,210评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,307评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,346评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,133评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,546评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,849评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,019评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,702评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,331评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,030评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,260评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,871评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,898评论 2 351

推荐阅读更多精彩内容