Servlet 相关 API

全面总结了 Servlet 相关的 API ,以及各类之间的内在联系系。

Servlet 接口

所有的 Servlet 类都必须要直接或者间接是实现 Servlet 接口,因为 Servlet容器是通过调用 Servlet 接口的方法来和 Servlet 类进行数据的交换的。

这里的数据交换说的更细致点就是,Servlet 容器会把收到的 HTTP 请求报文的字节流对象(本质上就是 Socket 通信),转成字符串。将这种以字符串形式表示的数据,进行字符串解析,封装到相应的类的对象中进行存储。然后将这种装载了请求信息的对象传递给 Servlet 类,以此实现它们之间的通信。

这个封装了请求参数信息的对象就是 ServletRequest 接口类型的对象,也就是 request ,封装了 web 应用返回给客户端信息的对象就是 ServletResponse 接口类型的 response 对象。之所以要这样做,当然是面向对象编程思想的指导啊,难不成把这些请求和响应信息用一个字符串数组装起来吗?

该接口的五个方法

其中三个方法是 Servlet 对象的声明周期的三个方法

  • void init(ServletConfig config)该方法接收 Servlet容器传递过来的 ServletConfig 对象
  • void service(ServletRequest req, ServletResponse res),每次请求访问 Servlet 类时,Servlet 容器就会调用此方法
  • void destroy(),Servelt 实例对象被销毁之前,会调用此方法。

得到 Servlet 类的相关信息

  • String getServletInfo()
    • 一般用来返回编写这个 Servlet 类的作者名字、版本号等信息。
      有点类似于一个类的 toString() 方法,用来返回对这个 Servlet 类的一些描述信息
  • ServletConfig getServletConfig()
    • 返回封装了这个 Servlet 类配置信息的 ServletConfig 对象,也就是 JSP 中的 config 对象

GenericServlet

这是一个实现了 Servlet 和 ServletConfig 接口的抽象类。其实抽象类存在的意义就是帮助一个接口真正的实现类做一些事情,让真正实现该接口的实现类少做点事情,毕竟面向对象的核心思想就是不能写重复代码,所以搞一个抽象类来替其他类写一部分代码。

比如,如果自己定义一个类来实现 Servlet 接口的时候,就需要手动的声明一个全局变量来接收,由 Servlet容器传递给init(ServletConfig config)方法的 ServletConfig 对象,才能够让其他方法也能使用到 ServletConfig 对象。这样的话,每一个 Servlet 类都需要手工做一次这种重复工作,这显然不符合面向对象的设计思想。

所以,这里提供了一个抽象类 GenericServlet 来完成这件事,在这各类中写一遍就可以了,其他 Servlet 类不再需要写重复代码了。自定义的 Servlet 类只需要继承这个抽象类即可,同样还是 Servlet 类,而且用起来更省事。

GenericServlet 类到底做了什么?

完成上述工作的具体方式是这样的,此类新增了一个无参的init()方法,是为了避免它的子类去重写init(ServletConfig config)方法,而且每次还都需要显示的使用super.init(ServletConfig)来调用 GenericServlet 类的方法,使得它特意做的工作失效了。

所以,提供了一个无参的init()方法,子类只需要重写无参的init()方法,在此方法内部完成部分初始化相关的工作就可以了。因为 GenericServlet 类实现了 Servlet 接口的init(ServletConfig config)时在该方法的最后一行调用了无参的init()方法。这就相当于说它的子类重写的init()方法会被当做初始化方法一样调用,它也是初始化方法中的一部分。仔细思考这些思路的话,发现这里面深层次的含义就是 JavaSE 部分那些基本概念的应用啊,不懂这些基本概念,是不可能设计的出来这种方法的,也不可能理解得了别人的想法。

全局的 ServletConfig 对象仍然是由 GenericServlet 类来保管的。正确的理解,应该是一个 Servlet 实例对象内部持有了一个 ServletConfig 对象,它们是组合关系。

总结下的话,GenericServlet 类重写了 Servlet 接口的有参的init()方法,把 Servlet容器传递过来的和这个 Servlet 类对象一一对应的 ServletConfig 对象保存为一个全局变量,将 config 对象作为一个属性去持有。并提供了一个无参的init()方法供他的子类去使用。

HttpServlet

WEB 开发用的是 HTTP 协议,所以肯定要针对 HTTP 协议做了一下个性化的功能填充。

HttpServlet 类到底做了什么?

该类的核心点就是它重写了父类的void service(ServletRequest req, ServletResponse res)方法,在此方法内部把 request 和 response 转换成 Http 类型的对象,然后调用它自己新增的service(HttpServletRequest req, HttpServletResponse resp)方法,在此内部根据 HTTP 请求方法,将请求分发到各个和 HTTP 的几种请求方式对应的方法去处理。自定义的 Servlet 只需要继承 HttpServlet ,并重写需要的方法就可以了。常用的有 doGet() 和 doPost() 两种方法!

也就是说 HttpServlet 把 Servlet 接口的service()方法给实现了,然后屏蔽了,子类只需要重写相应的doGet()doPost()就可以了。限于篇幅,只保留了部分核心源码:

String method = req.getMethod();//获取请求方式
//然后是7个equals()的判断,因为HTTP协议一共有7种请求方式
if (method.equals(METHOD_GET)) {
    doGet(req, resp);
} 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 {
}

总结下,HttpServlet 实现了 Servlet 接口的service()方法,并提供了根据doGet()doPost()等根据请求方式命名的方法,供它的子类去使用。它根据请求方法类型做了更为细致的分发,真正的 Servlet 类只需要根据请求类型重写对应的方法即可。比如,Get 请求就重写 doGet() 方法,Post 请求就重写 doPost() 方法。

学习感悟:其实编写 JavaSE 或者 JavaWeb 的代码,和使用框架是一样的道理,都需要遵循它的规则才行,在它的规定下进行编码。从这个角度来说,他们也是框架!用别人的东西,当然要受别人的限制啊。

这个道理其实可以应用到任何地方,就好像拿笔写字,只有用笔尖那头才能写字,拿着笔盖怎么写得到呢?这就是笔的规则,要使用它,就要遵循它的这个规则。在这个世界生存,也同样需要遵循这个世界的规则。当然做人不能什么规则都遵守,这样的人永远不会有大成就。善于、敢于打破规则的人才能成事。

ServletRequest 接口

浏览器以字节流的方式把数据发送到 Servlet 容器,Servlet 容器把字节流转成字符串后,再封装到 ServletRequest 对象中去。最后交给 Servlet 程序以面向对象的方法来使用这个信息。当然会封装很多个方法,然后每个方法返回一些相关的信息,面向对象不就是干这个事情的吗?

Servlet 中拿到的 ServletRequest 接口的对象和 JSP 中名字为 request 的对象是同一个对象,只是 JSP 中命名好了,Servlet 中没有指定命名方式而已。

ServletResponse

它和 ServletRequest 是一样的道理, Servlet 程序通过面向对象的方式给这个 response 对象设定相应信息,然后 Servlet 容器再把这些信息转成 HTTP 协议响应报文,返回给浏览器。

Servlet 中拿到的 ServletResponse 接口的对象和 JSP 中名字为 response 的对象是同一个对象,只是 JSP 中命名好了,Servlet 中没有指定命名方式而已。

ServletConfig

Servlet 容器会把 Servlet 类的初始化参数的 name 和 value 值封装到该类中,并提供了一个getInitParam(String name)的方法返回 name 对应的 value 值。尽管没有看过 ServletConfig 对象的源码,但是通过学习其他 MVC 框架源码后,在此不负责任的猜测,该接口的实现类肯定是用一个 Map 对象来存储这些信息的。并且提供了一个 getServletContext()方法获得 ServletContext 类型的 application 对象。

ServletContext

对于一个 web 应用,Servlet 容器只会给它创建一个 ServletContext 对象,也就是 JSP 中的 application 对象。该对象封装了 web.xml 中的所有的信息,当然也会包括它的初始化参数信息。查看该接口的源码,就可以知道它几乎封装了整个 web.xml 中的配置信息。

Servlet/JSP 应用程序中,不仅可以用注解的方式配置 Servlet 还可以用 xml 的方式。两者各有优点,但是 xml 的方式明显更牛,权限更高,可以覆盖注解的配置。这个例子还能够证明, web.xml 和注解可以同时存在,所以说合理的配合两者运用,才是最明智的选择。世间万物都是如此!

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

推荐阅读更多精彩内容

  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,217评论 11 349
  • Servlet Interface 是Java Servlet API的核心抽象。所有的servlets都直接或者...
    Lucky_Micky阅读 1,683评论 2 2
  • 在学习Servlet是找到一篇不错的文章,转载一下。学习心得,Servlet其实只是个接口,相当于是定义了一个标准...
    君子若莲阅读 1,204评论 1 16
  • Servlet、GenericServlet、HttpServlet Servlet 对于web容易来说,所有se...
    六尺帐篷阅读 1,358评论 0 4
  • 这间租房的唯一窗户旁是一面更衣镜。或许因为在被原主人购买后拉回家的过程里受了颠簸,镜子上有三道横贯或斜贯镜面的裂痕...
    半点正经阅读 269评论 0 0