Java Servlet 是什么?

本资料由知乎整理而来
链接:[https://www.zhihu.com/question/21416727/answer/690289895]

Servlet是Server Applet的缩写,意为“运行在服务端的小程序”。Servlet本身在Tomcat中是“非常被动”的一个角色,处理的事情也很简单,即负责处理具体的业务逻辑。网络请求与响应不是他的主要职责,所谓的Request和Response是Tomcat传给它,用来处理业务逻辑的工具,它本身不处理这些。

Servlet的前世今生

Tomcat其实是Web服务器和Servlet容器的结合体。Web服务器的作用就是将某个主机上的资源映射为一个URL供外界访问。Servlet容器,顾名思义里面存放着Servlet对象。
要通过Web服务器映射的URL访问资源必须要写程序处理请求,主要3个过程:

  • 接收请求
  • 处理请求
  • 响应请求

任何一个应用程序,必然包括这三个步骤。其中接收请求和响应请求是共性功能,且没有差异性,于是就把接收和响应两个步骤抽取成Web服务器:
在这里插入图片描述
处理请求的逻辑是不同的,于是抽取出来做成Servlet,交给程序员自己编写。随着后期互联网发展,出现了三层架构,所以一些逻辑就从Servlet抽取出来,分担到Service和Dao:
在这里插入图片描述

但是Servlet并不擅长往浏览器输出HTML页面,所以出现了JSP。
Spring家族出现后,Servlet开始退居幕后,取而代之的是方便的SpringMVC。SpringMVC的核心组件DispatcherServlet其实本质就是一个Servlet。但它已经自立门户,在原来HttpServlet的基础上,又封装了一条逻辑。

JavaWeb三大组件(Servlet / Filter / Listener)

从Tomcat开始,我们再也没写过main方法。以前,一个main方法启动,程序间的调用井然有序,我们知道程序所有流转过程。

但是到了Javaweb后,Servlet/Filter/Listener一路下来我们越学越沮丧。没有main,也没有new,写一个类然后在web.xml中配个标签,它们就这么兀自运行了。

其实,这一切的一切,简单来说就是“注入”和“回调”。想象一下,Tomcat里有个main方法,假设是这样的:
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

大部分工作,框架都已经帮我们做了。只要我们实现xxx接口,它会帮我们创建实例,然后搬运(接口注入)到它合适的位置,然后一套既定的流程下来,肯定会执行到。

如何编写一个Servlet

首先,我们心里必须有一个信念:我们都是菜鸡,框架肯定不会让我们写很难的代码,所以Servlet既然交给我们实现,肯定是很简单的!
Tomcat仅仅提供了javax.servlet接口,这是打算让我自己去实现?不,不可能的,肯定是因为太简单了。

查看接口方法:
在这里插入图片描述
五个方法,最难的地方在于形参,然而Tomcat会事先把形参对象封装好传给我…除此以外,既不需要写TCP连接数据库,也不需要解析HTTP请求,更不需要把结果转成HTTP响应,request对象和response对象已经帮我搞定了。
Tomcat之所以放心地交给我们实现,是因为Servlet里主要写的代码都是业务逻辑代码,和原始的、底层的解析、连接等没有丝毫关系。最难的几个操作,已经给你封装成形参传进来了。也就是说,Servlet虽然是个接口,但实现类只是个空壳,我们写点业务逻辑就好了。

总的来说,Tomcat已经替我们完成了所有“菜鸡程序员搞不定的骚操作”,并且传入三个对象:ServletConfig、ServletRequest、ServletResponse。
接下来,分析这三个对象是什么含义:

ServletConfig:
翻译过来就是“Servlet配置”。我们在哪配置Servlet来着?web.xml嘛。我们不必自己用dom4j解析xml得到对象,Tomcat已经帮我们搞定了。
在这里插入图片描述
也就是说,servletConfig对象封装了servlet的一些参数信息。如果需要,我们可以从它获取。

ServletRequest、ServletResponse

这两个对象其实是Tomcat处理的并封装好了的,不需要Servlet操心。很多人看待HTTP和Request/Response的眼光过于分裂。它们的关系就像菜园里的大白菜和餐桌上的酸辣白菜一样。HTTP请求到了Tomcat后,Tomcat通过字符串解析,把各个请求头(Header),请求地址(URL),请求参数(QueryString)都封装进了Request对象中。通过调用下列方法,可以得到浏览器当初发送的请求信息。

request.getHeader();
request.getUrl();
request.getQueryString();
...

至于Response,Tomcat传给Servlet时,它还是空的对象。Servlet进行逻辑处理后得到结果,最终通过response.write()方法,将结果写入response内部的缓冲区。Tomcat会在Servlet处理结束后,拿到response,遍历里面的信息,组装成HTTP响应发给客户端。
在这里插入图片描述

Servlet接口有5个方法,其中init、service、destroy是生命周期方法。init和destroy各自只执行一次,即Servlet创建和销毁时。而service会在每次有新请求到来时被调用。也就是说,我们主要的业务代码需要写在service中。
但是,浏览器发送请求最基本的有两种:Get/Post,于是我们必须这样写:
在这里插入图片描述
这样写看起来有点麻烦。我不想直接实现javax.servlet接口,有没有办法简化这个操作啊?
于是,菜鸡程序员找了下,发现了GenericServlet,是个抽象类
在这里插入图片描述
我们发现GenericServlet做了以下改良:

  • 提升了init方法中原本是形参的servletConfig对象的作用域(通过赋值给成员变量),方便其他方法使用;
  • init方法中还调用了一个init空参方法,如果我们希望在servlet创建时做一些什么初始化操作,可以继承GenericServlet后,覆盖init空参方法;
  • 由于其他方法内也可以使用servletConfig,于是写了一个getServletContext方法;

但是最重要的service()竟然是空的,于是放弃GenericServlet,继续寻找,又发现了抽象类 HttpServlet:
在这里插入图片描述
HttpServlet 继承了GenericServlet。GenericServlet本身是一个抽象类,有一个抽象方法service。查看源码发现,HttpServlet已经实现了service方法:
在这里插入图片描述

好了,也就是说HttpServlet的service方法已经替我们完成了复杂的请求方法判断。

但是,我翻遍整个HttpServlet源码,都没有找出一个抽象方法。所以为什么HttpServlet还要声明成抽象类呢?

看一下HttpServlet的文档注释:
在这里插入图片描述
一个类声明成抽象方法,一般有两个原因:

有抽象方法
没有抽象方法,但是不希望被实例化
HttpServlet做成抽象类,仅仅是为了不被实例化。
在这里插入图片描述
HttpServlet 为什么不希望被实例化,且要求子类重写doGet、doPost等方法呢?

我们来看一下源码:protected修饰,希望子类能重写
在这里插入图片描述

如果我们没重写会怎样?
在这里插入图片描述
浏览器页面会显示:405(http.method_get_not_supported)
也就是说,HttpServlet虽然在service中帮我们写了请求方式的判断。但是针对每一种请求,业务逻辑代码是不同的,HttpServlet无法知晓子类想干嘛,所以就抽出七个方法,并且提供了默认实现:报405、400错误,提示请求不支持。

但这种实现本身非常鸡肋,简单来说就是等于没有。所以,不能让它被实例化,不然调用doXxx方法是无用功。
在这里插入图片描述

Filter用到了责任链模式,Listener用到了观察者模式,Servlet也不会放过使用设计模式的机会:模板方法模式。上面的就是。关于此模式请点击连接:https://zhuanlan.zhihu.com/p/64749458

如何写一个Servet?
不用实现javax.servlet接口
不用继承GenericServlet抽象类
只需继承HttpServlet并重写doGet()/doPost()
父类把能写的逻辑都写完,把不确定的业务代码抽成一个方法,调用它。当子类重写该方法,整个业务代码就活了。这就是模板方法模式

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值