Servlet介绍,使用

1.Servlet介绍

Servlet其实就是Server Applet(运行在服务端的小程序),是运行在 Web 服务器上,能够创建动态内动容的小型 Java 程序。使用Java语言实现的一个接口,属于面向企业级Java的一部分

Servlet 通常通过 HTTP(超文本传输协议)接收和响应来自 Web 客户端的请求。Servlet实例是由web服务器创建的,它是单例多线程的。单例是指Servlet的实例只有一个,多线程是指每次客户端的请求,web服务器都会从线程池中分配一个工作线程去执行Servlet的service()方法。

所谓Tomcat其实是Web服务器和Servlet容器的结合体,

web服务器也是一个应用程序,专门用于处理TCP连接、接受HTTP请求、响应数据等底层的功能,简单的说就是处理网络请求与响应。

2.Servlet规范

web服务器如何将封装好的请求传递给web应用,以及web应用如何将响应结果数据传递给web服务器,以及二者交互的数据的格式是怎样的,对于这种通用的问题,制定一个统一的标准最好了,所有的web项目都可以按照这个标准来开发,web服务器也按照这个标准来实现。这对于Java来说很简单,那就是抽象成为一个接口(interface)即可。

这就是Servlet,Servlet定义了通过Java开发web应用处理网络请求以及响应数据的接口规范。

Servlet就是一个sun制订的使用Java语言开发Web项目的一个规范,我们使用Servlet规范开发的Web项目,就能够运行在同样实现了Servlet规范的Web服务器中,这样的好处是,解析客户端网络请求、线程复用、响应数据给客户端等一系列底层的网络编程工作都由Web服务器帮我们完成了,而我们的“Web项目”仅仅需要编写Servlet的实现,在实现中仅仅需要编写业务逻辑就行了,随后我们还需要将指定的Servlet实现与指定的请求路径绑定。

3.Tomcat和Servlet的关系

Tomcat 是Web应用服务器,是一个Servlet/JSP容器,Tomcat 作为Servlet容器,负责处理客户请求,把请求传送给Servlet,并将Servlet的响应传送回给客户.而Servlet是一种运行在支持Java语言的服务器上的组件. Servlet最常见的用途是扩展Java Web服务器功能,提供非常安全的,可移植的,易于使用的CGI替代品.

①:Tomcat将http请求文本接收并解析,然后封装成HttpServletRequest类型的request对象,所有的HTTP头数据读可以通过request对象调用对应的方法查询到。

②:Tomcat同时会要响应的信息封装为HttpServletResponse类型的response对象,通过设置response属性就可以控制要输出到浏览器的内容,然后将response交给Tomcat,Tomcat就会将其变成响应文本的格式发送给浏览器

Java Servlet API 是Servlet容器(Tomcat)和Servlet之间的接口,它定义了serlvet的各种方法,还定义了Servlet容器传送给Servlet的对象类,其中最重要的就是ServletRequest和ServletResponse。所以说我们在编写Servlet时,需要实现Servlet接口,按照其规范进行操作。

Tomcat才是与客户端直接打交道的家伙,他监听了端口,请求过来后,根据url等信息,确定要将请求交给哪个Servlet去处理,然后调用那个Servlet的service方法,service方法返回一个response对象,Tomcat再把这个response返回给客户端。

下文所说的web服务器不特殊说明都是指的是Tomcat。

4.CGI与FastCGI

4.1 CGI

CGICommon Gateway Interface(通用网关接口)的缩写,它是一种标准的Web服务器和应用程序交互的协议。它定义了在Web服务器和应用程序之间传递数据的规范,通过这种方式,Web服务器可以调用外部的应用程序来处理HTTP请求,并将结果返回给客户端。

4.2 FastCGI

FastCGI是CGI的一种变体,它采用了进程复用的方式来提高性能。传统的CGI模式每次请求都会创建一个新的进程来处理,因此一旦访问量过大,web服务器要承担相当大 负载。而FastCGI则通过保持一组预先创建好的进程,来避免重复的进程创建和销毁操作,从而提高了性能。FastCGI在CGI的基础上增加了一些额外的功能,例如连接的复用、多线程支持等。

5.使用Servlet

Servlet接口定义的是一套处理网络请求的规范,所有实现Servlet的类,都需要实现它那五个方法,其中最主要的是两个生命周期方法 init()destroy(),还有一个处理请求的service(),也就是说,所有实现Servlet接口的类,或者说,所有想要处理网络请求的类,都需要:

  • init( ),当Servlet第一次被请求时,Servlet容器就会开始调用这个方法来初始化一个Servlet对象出来,但是这个方法在后续请求中不会在被Servlet容器调用只能调用一次,调用这个方法时,Servlet容器会传入一个ServletConfig对象进来从而对Servlet对象进行初始化。

  • service()方法,每当请求Servlet时,Servlet容器就会调用这个方法。第一次请求时,Servlet容器会先调用init()方法初始化一个Servlet对象出来,然后会调用它的service()方法进行工作(根据不同的请求来调用不同的方法,主要是doGet()和doPost()),但在后续的请求中,Servlet容器只会调用service方法了。

  • destory(),最后服务器关闭时,需要销毁这个Servlet对象,执行destroy()方法

5.1 HttpServlet

  • ServletConfig接口:用来定义一个在初始化期间将配置信息(Servlet名、初始化参数等)传递给Servlet的Servlet配置对象。它的主要实现子类是StandardWrapperFacade类。

  • GenericServlet(Generic-通用的)抽象类:用于包装Servlet接口,其中提供了很多Servlet接口的默认实现,这样我们实现Servlet的时候,就不必实现Servlet接口的所有方法,只重写核心方法即可。

  • HttpServlet抽象类:听这个类的名字就大概能够知道,HttpServlet类是专门用于处理http请求的Servlet类。它继承了GenericServlet类,其中有很多http请求专用的处理方法(例如:doGet、doPost、doPut等等方法)

服务器启动时(web.xml中配置load-on-startup=1,默认为0)或者第一次请求该Servlet时,就会初始化一个Servlet对象,也就是会执行初始化方法init(ServletConfig conf)

该Servlet对象去处理所有客户端请求,在service(ServletRequest req,ServletResponse res)方法中执行。最后服务器关闭时,才会销毁这个Servlet对象,执行destroy()方法。

5.2 继承HttpServlet

1
2
3
4
5
6
7
8
9
10
11
12
public class MyHttpServlet extends HttpServlet {

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}

5.3 配置web.xml

在web.xml中配置自己写的Servlet,因为要让容器知道请求到达哪个Servlet。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<web-app>

<Servlet>
<Servlet-name>FirstServlet</Servlet-name>
<Servlet-class>com.example.MyHttpServlet</Servlet-class>
</Servlet>
<Servlet-mapping>
<Servlet-name>FirstServlet</Servlet-name>
<url-pattern>/first</url-pattern>
</Servlet-mapping>

<Servlet>
<Servlet-name>SecondServlet</Servlet-name>
<Servlet-class>com.example.SecondServlet</Servlet-class>
</Servlet>
<Servlet-mapping>
<Servlet-name>SecondServlet</Servlet-name>
<url-pattern>/second</url-pattern>
</Servlet-mapping>

</web-app>

可以配置多个Servlet,对应不同的访问路径。

web服务器首先根据请求路径查找url-pattern,得到Servlet-name,再根据这个name查找Servlet,就找到了我们定义的Servlet。

6.相关代码

6.1 service方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {

HttpServletRequest request;
HttpServletResponse response;

try {
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
} catch (ClassCastException e) {
throw new ServletException("non-HTTP request or response");
}
service(request, response);
}

然后到下面的service方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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)) {
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}

} else if (method.equals(METHOD_POST)) {
doPost(req, resp);

} ... ...

} else {
//error
}
}

到现在就知道我们为什么要重写doGet和doPost方法了吧,因为最终程序调用到的就是我们自己写的doGet和doPost方法

6.2 ServletConfig

就是Servlet配置,还记得web.xml吗,其实就是Tomcat解析web.xml,获取Servlet配置,通过反射创建Servlet实例。

6.3 Request/Response

Http请求到了Tomcat之后,Tomcat通过一系列操作将请求头,请求地址,参数等信息封装进了request对象中。

返回信息时,Tomcat会得到返回response对象,遍历里面的信息,组装成http响应发给客户端。

7. 不使用Servlet规范开发Web项目行不行呢?

那肯定也是可以的。只不过这需要我们自己来解析请求、返回响应。

当然,一个大型项目业务众多,各种请求,甚至包括文件上传、下载之类的,网络编程的实现远比这个案例复杂,那就相当于你自己开发一个项目的同时还顺便开发一个Web服务器了。当然,这就比较夸张了,实际上我们基于Netty就能比较轻松实现一个Web服务器,自己解析请求、响应,就能构建一个不遵循Servlet规范的Web项目。

另外,在“Web应用”层面,目前我们也很少亲自实现Servlet了,因为有了更好的Web框架帮助我们对Servlet进行了封装,比如Spring MVC,它就是基于Servlet API封装的一种框架,但是在使用Spring MVC的时候,我们完全感受不到Servlet的存在,这就是框架的强大之处。而Spring 5.0又推出了底层基于Netty的异步非阻塞的响应式Web框架Spring WebFlux,Spring WebFlux开发的Web项目就可以不运行在Servlet容器中,比如它可以直接运行在Netty服务器中


博客说明

文章所涉及的资料来自互联网整理和个人总结,意在于个人学习和经验汇总,不用于任何的商业用途。如有侵权,请联系本人删除。谢谢!


Servlet介绍,使用
https://nanchengjiumeng123.top/2024/01/10/framework/spring/Spring MVC/1.Servlet介绍,使用/
作者
Yang Xin
发布于
2024年1月10日
许可协议