Servlet规范总结

Servlet接口

Servlet规范的核心接口即是Servlet接口,它是所有Servlet类必须实现的接口,在Java Servelt API中已经提供了两个抽象类方便开发者实现Servlet类,分别是GenericServlet 和 HttpServlet,GenericServlet定义了一个通用的、协议无关的Servlet,而HttpServlet则定义了Http协议的Servlet,这两个抽象类可以使Servlet类复用很多共性功能。

Servlet接口的核心方法为service方法,它作为处理客户端请求的处理方法,客户端发起的请求会被路由到对应的Servlet对象上,前面说到的HttpServlet类的service方法即为对http协议的GET、POST、PU、DELETE、HEAD、OPTIONS、TRACE等请求转发到各自处理方法中,对应着doGet、doPost、doPut、doDelete、doHead、doOptions、doTrace等方法,HTTPServlet提供了这些共性的处理逻辑,其他继承它的类就不用再各自实现,只需要在对应的方法做具体处理逻辑即可。例如我们做web开发时常常会自己定义一个Servlet,并在doGet和doPost方法中做业务逻辑处理。

一般来说,在Servlet容器中,每个Servlet类只能对应一个Servlet对象,所有调用此Servlet的都由同一个Servlet对象处理,但如果Servlet实现了SingleThreadModel接口则可能会在web容器中存在多个Servlet对象。对于web容器来说,实现了SingleThreadModel接口意味着一个Servlet对象对应着一条线程,所以此时Servlet的成员变量不存在线程安全问题。

Servlet的生命周期主要包括加载实例化、初始化、处理客户端请求、销毁。加载实例化主要是交由web容器完成,而其他三个阶段则对应Servlet的init、service和destroy方法。Servlet对象被创建出来后需要对其进行初始化操作,初始化工作可以放在以ServletConfig类型为参数的ini方法中,ServletConfig为web.xml配置文件中配置的对应的初始化参数,由web容器完成web.xml配置读取并封装成ServletConfig对象;当Servlet初始化完成后,开始接受客户端的请求,这些请求被封装成ServletRequest类型的请求对象和ServletResponse类型的响应对象,通过service方法处理请求并响应客户端;当一个Servlet需要从web容器中移除时,就会调用对应的destroy方法用于释放所有的资源,并且调用destroy方法之前要保证所有正在执行service方法的线程都完成执行。

ServletRequest接口

ServletRequest接口的实现类封装了客户端请求的所有信息,如果使用HTTP协议通信则包括HTTP协议的请求行和请求头。HTTP协议对应请求对象类型是HttpServletRequest类。

它提供了一些HTTP协议请求头部的获取方法,如getHeader、getHeaders和getHeaderNames;

它提供了一些获取请求路径的方法,如getContextPath、getServletPath和getPathInfo,对于路径变量,其中requestURI=contextPath+servletPath+pathInfo,而getRealPath方法则是获取某个相对路径对应的文件系统路径;

它提供了获取cookie的方法,如getCookies方法;提供了标识是否为HTTPS协议的方法,如isSecure方法;

它提供了获取客户端的语言环境的方法,如getLocale和getLocales,它们对应Http协议的Accept-Language头部;

它提供了获取客户端编码的方法,如getCharacterEncoding,对应http协议的 Content-Type头部。

ServletRequest接口的对象只在servlet的service方法或过滤器的doFilter方法作用域内有效,除非启用了异步处理调用了ServletRequest接口对象的startAsync方法,此时request对象会一直有效,直到调用AsyncContext的complete方法。另外,web容器通常会为了性能而不销毁ServletRequest接口的对象,而是重复利用ServletRequest接口对象。

ServletContext接口

ServletContext接口定义了运行了所有Servlet的web应用的视图。

它提供某个web应用的Servlet全局存储空间,某web应用对应的所有Servlet共有的各种资源和功能的访问。

它提供了获取web应用的部署描述配置文件的方法,例如getInitParameter和getInitParameterNames;

它提供了添加Servlet到ServletContext里面的方法,例如addServlet;

它提供了添加Filter过滤器到ServletContext里面的方法,例如addFilter;

它提供了添加Listener监听器到ServletContext里面的方法,例如addListener;

它提供全局的属性保存和获取功能,例如setAttribute、getAttribute、getAttributeNames和removeAttribute等;

所有Servlet及它们使用的类需要由一个单独的类加载器加载。每个实现ServletContext接口的对象都需要一个临时存储目录,Servlet容器必须为每个ServletContext分配一个临时目录,并可在ServletContext接口通过 javax.servlet.context.tempdir属性获取该目录。

ServletResponse接口

ServletResponse接口的对象封装了服务端要返回客户端的所有信息,如果是HTTP协议则包含了http的响应行、响应头和响应体。

为了提高效率,一般ServletResponse接口对响应提供了输出缓冲,其中getBufferSize用于获取缓冲区大小,setBufferSize用于设置缓冲区大小,flushBuffer强制刷出缓冲区,resetBuffer将清空缓冲区中的内容,但不清空请求头和状态码,isCommitted判断是否有任何响应字节已经返回给客户端,reset清空缓冲区内容,同时清空头信息和状态码。

ServletResponse接口对应HTTP协议的实现对象为HttpServletResponse。可以通过setHeader和addHeader方法往HttpServletResponse添加头部;可以通过sendRedirect将客户端重定向到另外一个地址;可以通过sendError将错误信息输出到客户端;

当ServletResponse接口关闭时,缓冲区中的内容必须立即刷到客户端,ServletResponse接口只在Servlet的service方法或过滤器的doFilter方法作用域内有效,除非它关联的ServletResponse接口调用了startAsync方法启用异步处理,此时ServletResponse接口会一直有效,直到调用AsyncContext的complete方法。另外,web容器通常会为了性能而不销毁ServletResponse接口对象,而是重复利用ServletResponse接口对象。

Filter接口

Filter接口允许Web容器对请求和响应做统一处理,例如统一改变HTTP请求内容和响应内容,它可以作用在某个Servlet或一组Servlet。

Web应用部署完成后,必须实例化好过滤器并调用其init方法,当请求进来时,获取第一个过滤器并调用doFilter方法,并传入ServletRequest对象、ServletResponse对象及过滤链FilterChain,doFilter方法负责过滤器链的下个实体的doFilter方法调用。当容器要移除某过滤器时必须先调用过滤器的destroy方法。

可以用“@WebFilter”注解或部署描述文件定义过滤器,XML配置形式使用元素定义,包括、和子节点,并使用定义web应用的Servlet和其他静态资源通过过滤器。

会话

Servlet没有提出协议无关的会话规定,而是每个通信协议自己规定,HTTP协议对应的会话接口是HttpSession。Cookie是常用的会话跟踪机制,其中Cookie的标准名字必须为JSESSIONID。另外一种会话跟踪机制则是URL重写,即在URL后面添加一个jsessionid参数,当支持Cookie和SSL会话的情况下不应该使用URL重写作为会话跟踪机制。

会话 ID 通过调用 HttpSession.getId()获取,且能在创建后通过调用HttpServletRequest.changeSessionId()改变。HttpSession对象必须限定在ServletContext级别,会话里面的属性不能在不同ServletContext之间共享。

Servlet可将某对象以键值对形式保存到HttpSession中,处于同个ServletContext且相同会话的任意Servlet都可以使用会话中保存的对象。如果某些对象想要在保存到会话或从会话中移除时得到通知,可以让某个对象实现HttpSessionBindingListener接口,里面的valueBound和valueUnbound分别会在对应时刻被触发。

Servlet容器默认会话超时时间,可以通过HttpSession的getMaxInactiveInterval方法获取和setMaxInactiveInterval 方法设置。

分布式环境中,会话的所有请求在同一时间必须仅被一个JVM处理,分布式容器迁移会话时会通知实现了HttpSessionActivationListener接口的所有会话属性。

注解

web应用中,使用了注解的类只有被放到WEB-INF/classes目录中或WEB-INF/lib目录下的jar中注解才会被Web容器处理。web.xml配置文件的元素的metadata-complete默认为false,表示Web容器必须检查类的注解和web fragments,否则忽略注解和web fragments。

@WebServlet注解用于在Web项目定义Servlet,必须指定urlPatterns或value属性,默认的name属性为全限定类名,@WebServlet注解的类必须继承javax.servlet.http.HttpServlet类;

@WebFilter注解用于在Web项目定义Filter,必须指定urlPatterns,servletNames或value属性,默认的filterName属性为全限定类名,@ WebFilter注解的类必须实现 javax.servlet.Filter;

@WebInitParam注解用于指定传递到Servlet或Filter的初始化参数,它是WebServlet和WebFilter注解的一个属性;

@WebListener注解用于定义Web应用的各种监听器,@WebListener注解的类必须实现以下接口中的其中一个:

javax.servlet.ServletContextListener

javax.servlet.ServletContextAttributeListener

javax.servlet.ServletRequestListener

javax.servlet.ServletRequestAttributeListener

javax.servlet.http.HttpSessionListener

javax.servlet.http.HttpSessionAttributeListener

javax.servlet.http.HttpSessionIdListener;

@MultipartConfig注解用于指定Servlet请求期望是mime/multipart类型。

可插拔

为了给Web开发人员提供更好的可插拔性和更少的配置,可以在一个库类或框架jar包的META-INF目录指定web fragment,即web-fragment.xml配置文件,它可以看成是Web的逻辑分区,web-fragment.xml与web.xml包含的元素基本都相同。部署期间,Web容器会扫描WEB-INF/lib目录下的jar包的META-INF/web-fragment.xml文件,并根据配置文件生成对应的组件。

一个Web应用可能会有一个web.xml和若干个web-fragment.xml文件,Web容器加载时会涉及顺序问题,有两种方式定义他们加载的顺序:绝对顺序,web.xml中的元素用于描述加载资源的顺序;相对顺序,web-fragment.xml中的元素用于描述web-fragment.xml之间的顺序。

请求分发器

请求分发器是把请求转发给另外一个Servlet处理,或在响应中包含另外一个Servlet的输出,RequestDispatcher接口提供了此实现机制。可以通过ServletContext的getRequestDispatcher方法和getNamedDispatcher方法分别通过路径或Servlet名称作为参数获取对应Servlet的RequestDispatcher。

请求分发器有include和forward两个方法,include方法是将目标Servlet包含到当前的Servlet中,主控制权在当前Servlet上;forward方法是将当前Servlet的请求转移到目标Servlet上,主控权在在目标Servlet上,当前Servlet的执行终止。

Web应用

Web应用和ServletContext接口对象是一对一的关系,ServletContext 对象提供了一个 Servlet 和它的应用程序视图。Web应用可能包括Servlet、JSP、工具类、静态文件、客户端Java Applet等等,Web应用结构包括WEB-INF/web.xml文件、WEB-INF/lib/目录下存放所有jar包、WEB-INF/classes/目录存放所有类、META-INF目录存放工程的一些信息、其他资源根据具体目录存放。一般WEB-INF 目录下的文件都不能由容器直接提供给客户端访问,但WEB-INF目录中的内容可以通过 Servlet 代码调用 ServletContext 的 getResource 和 getResourceAsStream 方法来访问,并可使用 RequestDispatcher 调用公开这些内容。

Web容器用于加载WAR文件中Servlet的类加载器必须提供getResource方法用于加载WAR文件的JAR包中包含的任何资源。容器不允许Web应用程序覆盖或访问容器的实现类。一个类加载器的实现必须保证对部署到容器的每个 Web应用调用Thread.currentThread.getContextClassLoader()返回一个规定的ClassLoader实例。部署的每个 Web 应用程序的ClassLoader实例必须是一个单独的实例。

服务器应该能在不重启Web容器的情况下更新一个Web应用程序,而更新Web应用程序时Web容器应该提供可靠的方法保存这些Web应用的会话。

如果调用response的sendError方法或如果Servlet产生一个异常或错误传播给容器时,容器要按照Web应用部署描述文件中定义的错误页面列表,根据状态码或异常试图返回一个匹配的错误页面。如果Web应用部署描述文件的error-page元素没有包含exception-type或error-code子元素,则错误页面使用默认的错误页面。

Web应用的部署描述符中可以配置欢迎文件列表,当一个Web的请求URI没有映射到一个Web资源时,可以从欢迎文件列表中按顺序匹配适合的资源返回给客户端,如欢迎页为index.html,则http://localhost:8080/webapp请求实际变为http://localhost:8080/webapp/index.html。如果找不到对应的欢迎页则返回404响应。

当一个Web应用程序部署到容器中时,在Web应用程序开始处理客户端请求之前,必须按照下述步骤顺序执行:

① 实例化部署描述文件中元素标识的每个事件监听器的一个实例。

② 对于已实例化的实现了 ServletContextListener 接口的监听器实例,调用 contextInitialized()方法。

③ 实例化部署描述文件中元素标识的每个过滤器的一个实例,并调用每个过滤器实例的 init()方法。

④ 包含元素的元素,根据load-on-startup元素值定义的顺序为每个Servlet实例化一个实例,并调用每个servlet实例的init()方法

对于不包含任何Servlet、Filter或Listener的Web应用,或使用注解声明的Web应用,可以不需要web.xml部署描述符。

Servlet映射

对于请求的URL,Web容器根据最长的上下文路径匹配请求URL,然后匹配Servlet,Servlet的路径是由整个请求URL减去上下文和路径参数,匹配规则如下:

Web容器尝试匹配一个精确的Servlet路径,成功则选择该Servlet。

Web容器递归尝试匹配最长路径前缀。

如果URL最后包含扩展名,例如.jsp,Web容器将试图匹配一个专门用于处理此扩展名的Servlet。

如果前三个规则都没匹配上,则匹配一个默认的Servlet。

部署描述文件

所有 Servlet 容器的 Web 应用程序部署描述文件需要支持以下类型的配置和部署信息:

①ServletContext 初始化参数

②Session 配置

③Servlet 声明

④Servlet 映射

⑤应用程序生命周期监听器类

⑥过滤器定义和过滤器映射

⑦MIME 类型映射

⑧欢迎文件列表

⑨错误页面

⑩语言环境和编码映射

⑪安全配置,包括 login-config,security-constraint,security-constraint,security-role-ref 和 run-as

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

推荐阅读更多精彩内容

  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,169评论 11 349
  • 这部分主要是与Java Web和Web Service相关的面试题。 96、阐述Servlet和CGI的区别? 答...
    杂货铺老板阅读 1,397评论 0 10
  • Servlet Interface 是Java Servlet API的核心抽象。所有的servlets都直接或者...
    Lucky_Micky阅读 1,668评论 2 2
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,560评论 18 399
  • 四月末 青岛的阳光温如薄纱 一推门 便看到落败的花 夏天是快要来了吧 每天有多少人来到这里 在栈桥上留影 以证明自...
    宋予屿阅读 471评论 6 3