一文搞清楚Servlet是什么(新手必看)
Servlet 是 Server 与 Applet 的缩写,是服务器小程序的意思,是 Sun 公司提供的一种用于开发动态 Web 资源的技术。
Servlet 是基于 Java 语言的 Web 编程技术,部署在服务器的 Web 容器里,获取客户端的访问请求,并根据请求生成响应信息返回客户端。Java Web应用程序请求处理流程如下图所示:

图 1 Java Web应用程序请求处理流程
Servlet 是平台独立的 Java 类,编写一个 Servlet,实际上就是按照 Servlet 规范编写一个 Java 类。Servlet 被编译为平台独立的字节码,可以被动态地加载到支持 Java 技术的 Web 服务器中运行。
Servlet 容器(也称为 Servlet 引擎)是 Web 服务器或应用程序服务器的一部分,用于在发送的请求和响应之上提供网络服务,解码基于多用途互联网邮件扩展(Multipurpose Internet Mail Extensions,MIME)的请求,格式化基于 MIME 的响应。
Servlet 不能独立运行,必须被部署到 Servlet 容器中,由容器来实例化和调用 Servlet 的方法。
Tomcat 是 Web 应用服务器,是一个 Servlet/JSP 容器。Tomcat 作为 Servlet 容器,负责处理客户请求,把请求传送给 Servlet,并将 Servlet 的响应传送回客户,而 Servlet 是一种运行在支持 Java 语言的服务器上的组件。Servlet 最常见的用途是扩展 Java Web 服务器功能,提供非常安全的、可移植的、易于使用的 CGI 替代品。
Servlet的主要功能如下:
Servlet 对象是 Servlet 容器创建的,生命周期方法都由容器调用。这点和之前所编写的代码有很大不同。在今后的学习中我们会看到,越来越多的对象交给容器或框架来创建,越来越多的方法由容器或框架来调用,开发人员要尽可能多地将精力放在业务逻辑的实现上。
Servlet 容器会为每个自动装入选项的 Servlet 创建一个实例。所以,每个 Servlet 类必须有一个公共的无参数的构造器。
Servlet 在启动后不立即初始化,而是收到请求后进行。在 web.xml 文件中用 <load-on-statup>……</load-on-statup> 对 Servlet 进行预先初始化。初始化失败后,执行 init() 方法抛出 ServletException 异常,Servlet 对象将会被垃圾回收器回收,当客户端第一次访问服务器时加载 Servlet 实现类,创建对象并执行初始化方法。
Servlet 给客户端的响应由一个 ServletResponse 对象代表。对于到达客户端的请求,服务器创建特定于该请求的一个“请求”对象和一个“响应”对象。调用 service() 方法,这个方法可以调用其他方法来处理请求。
service() 方法会在服务器被访问时调用,在 Servlet 对象的生命周期中 service() 方法可能被多次调用。由于 web-server 启动后,服务器中公开的部分资源将处于网络中,当网络中的不同主机(客户端)并发访问服务器中的同一资源时,服务器将开设多个线程处理不同的请求,多线程同时处理同一对象时,有可能出现数据并发访问的错误。
另外需注意,多线程难免同时处理同一变量(如对同一文件进行写操作),且有读写操作时,必须考虑是否需要添加同步操作。添加同步操作时,添加范围不要过大,否则有可能使程序变为纯粹的单线程,大大削弱系统性能,只需要做到多个线程安全地访问相同的对象就可以了。
Servlet 一旦终止,Servlet 实例即可被垃圾回收器回收,处于“卸载”状态。如果 Servlet 容器被关闭,Servlet 也会被卸载。一个 Servlet 实例只能初始化一次,但可以创建多个相同的 Servlet 实例,如相同的 Servlet 可以在根据不同的配置参数连接不同的数据库时创建多个实例。
init() 方法的声明格式如下:
这个 ServletConfig 对象负责向 Servlet 传递服务设置信息,如果传递失败就会发生 ServletException 异常,Servlet 对象就不能正常工作。init() 方法只被调用一次,即在 Servlet 第一次被请求加载时调用该方法。
服务器将两个对象传递给该方法:
和 init() 方法不同的是,service() 方法可能被多次调用。我们已经知道,当后续的客户请求该 Servlet 对象服务时,服务器将启动一个新的线程,在该线程中,Servlet 对象调用 service() 方法响应客户的请求,也就是说,每个客户的每次请求都导致 service() 方法被调用,调用过程运行在不同的线程中,互不干扰。因此,不同线程的 service() 方法中的局部变量互不干扰,一个线程改变了自己的 service() 方法中局部变量的值不会影响其他线程的 service() 方法中的局部变量。
在 Servlet 的整个生命周期中,destroy() 方法也只被调用一次。需要注意的是,Servlet 对象一旦创建就会驻留在内存中等待客户端的访问,直到服务器关闭,或 Web 应用被移除出容器时,Servlet 对象才会被销毁。
Servlet 的处理过程如下图所示:

图 2 Servlet的处理过程
JSP 是一种实现普通静态 HTML 和动态 HTML 混合编码的技术,其并没有增加任何本质上不能用 Servlet 实现的功能。但是,在 JSP 中编写静态 HTML 更加方便,不必再用 println 语句来输出每一行 HTML 代码。
更重要的是,借助内容和外观的分离,页面制作中不同性质的任务可以方便地分开。比如,由页面设计者进行HTML设计,同时留出供Servlet程序员插入动态内容的空间。
既然 JSP 和 Servlet 都有自身的适用环境,那么能否扬长避短,让它们发挥各自的优势呢?答案是肯定的——模型-视图-控制器(Model-View-Controller,MVC)模式非常适合解决这一问题。
MVC 模式是软件工程中的一种软件架构模式,把软件系统分为 3 个基本部分,分别是模型(Model)、视图(View)和控制器(Controller):
在 JSP/Servlet 开发的软件系统中,这 3 个部分的描述如下图所示:

图 3 MVC模式
MVC 模式在 Web 开发中的好处非常明显,它规避了 JSP 与 Servlet 各自的短板,Servlet 只负责业务逻辑而不会通过 out.append() 动态生成 HTML 代码,在 JSP 中也不会充斥着大量的业务代码。这大大提高了代码的可读性和可维护性。
Servlet 程序在服务器运行,动态地生成 Web 页面。与传统的 CGI 技术相比,Servlet 具有高效率、易使用、功能强大、可移植性等特点。
Servlet 是基于 Java 语言的 Web 编程技术,部署在服务器的 Web 容器里,获取客户端的访问请求,并根据请求生成响应信息返回客户端。Java Web应用程序请求处理流程如下图所示:

图 1 Java Web应用程序请求处理流程
Servlet 是平台独立的 Java 类,编写一个 Servlet,实际上就是按照 Servlet 规范编写一个 Java 类。Servlet 被编译为平台独立的字节码,可以被动态地加载到支持 Java 技术的 Web 服务器中运行。
Servlet 容器(也称为 Servlet 引擎)是 Web 服务器或应用程序服务器的一部分,用于在发送的请求和响应之上提供网络服务,解码基于多用途互联网邮件扩展(Multipurpose Internet Mail Extensions,MIME)的请求,格式化基于 MIME 的响应。
Servlet 不能独立运行,必须被部署到 Servlet 容器中,由容器来实例化和调用 Servlet 的方法。
Tomcat 是 Web 应用服务器,是一个 Servlet/JSP 容器。Tomcat 作为 Servlet 容器,负责处理客户请求,把请求传送给 Servlet,并将 Servlet 的响应传送回客户,而 Servlet 是一种运行在支持 Java 语言的服务器上的组件。Servlet 最常见的用途是扩展 Java Web 服务器功能,提供非常安全的、可移植的、易于使用的 CGI 替代品。
Servlet的主要功能如下:
- 读取客户端发送到服务器的显式数据(表单数据);
- 读取客户端发送到服务器的隐式数据(请求报头);
- 服务器发送显式的数据到客户端(HTML);
- 服务器发送隐式的数据到客户端(状态代码和响应报头)。
Servlet的生命周期
应用程序中的对象不仅在空间上有层次结构的关系,在时间上也会因为处于程序运行过程中的不同阶段而表现出不同状态和不同行为,这就是对象的生命周期。Servlet 对象是 Servlet 容器创建的,生命周期方法都由容器调用。这点和之前所编写的代码有很大不同。在今后的学习中我们会看到,越来越多的对象交给容器或框架来创建,越来越多的方法由容器或框架来调用,开发人员要尽可能多地将精力放在业务逻辑的实现上。
1、Servlet的生命周期阶段
一个 Servlet 的生命周期由部署该 Servlet 的容器负责,除此之外,容器还提供请求分发、安全、并发控制等服务。Servlet 的生命周期可分为加载和实例化、初始化、请求处理、卸载 4 个阶段,当特定的请求被容器映射到某个Servlet时,容器会做以下操作。1) 加载和实例化
当启动 Servlet 容器时,容器首先查找一个配置文件 web.xml,这个文件记录了可以提供服务的 Servlet。每个 Servlet 被指定一个 Servlet 名,也就是这个 Servlet 实际对应的 Java 的完整 class 文件名。Servlet 容器会为每个自动装入选项的 Servlet 创建一个实例。所以,每个 Servlet 类必须有一个公共的无参数的构造器。
2) 初始化
当 Servlet 被实例化后,Servlet 容器将调用每个 Servlet 的 init() 方法来实例化每个实例,执行完 init() 方法之后,Servlet 处于“已初始化”状态。所以说,一旦 Servlet 被实例化,那么必将调用 init() 方法。Servlet 在启动后不立即初始化,而是收到请求后进行。在 web.xml 文件中用 <load-on-statup>……</load-on-statup> 对 Servlet 进行预先初始化。初始化失败后,执行 init() 方法抛出 ServletException 异常,Servlet 对象将会被垃圾回收器回收,当客户端第一次访问服务器时加载 Servlet 实现类,创建对象并执行初始化方法。
3) 请求处理
Servlet 被初始化以后,就处于能响应请求的就绪状态。每个对 Servlet 的请求由一个 ServletRequest 对象代表。Servlet 给客户端的响应由一个 ServletResponse 对象代表。对于到达客户端的请求,服务器创建特定于该请求的一个“请求”对象和一个“响应”对象。调用 service() 方法,这个方法可以调用其他方法来处理请求。
service() 方法会在服务器被访问时调用,在 Servlet 对象的生命周期中 service() 方法可能被多次调用。由于 web-server 启动后,服务器中公开的部分资源将处于网络中,当网络中的不同主机(客户端)并发访问服务器中的同一资源时,服务器将开设多个线程处理不同的请求,多线程同时处理同一对象时,有可能出现数据并发访问的错误。
另外需注意,多线程难免同时处理同一变量(如对同一文件进行写操作),且有读写操作时,必须考虑是否需要添加同步操作。添加同步操作时,添加范围不要过大,否则有可能使程序变为纯粹的单线程,大大削弱系统性能,只需要做到多个线程安全地访问相同的对象就可以了。
4) 卸载
当服务器不再需要 Servlet 实例或重新装入时,会调用 destroy() 方法,使用这个方法,Servlet 可以释放掉所有 init() 方法申请的资源。一个 Servlet 实例一旦终止,就不允许再次被调用,只能等待被卸载。Servlet 一旦终止,Servlet 实例即可被垃圾回收器回收,处于“卸载”状态。如果 Servlet 容器被关闭,Servlet 也会被卸载。一个 Servlet 实例只能初始化一次,但可以创建多个相同的 Servlet 实例,如相同的 Servlet 可以在根据不同的配置参数连接不同的数据库时创建多个实例。
2、与Servlet生命周期有关的方法
在 javax.servlet.Servlet 接口中,定义了针对 Servlet 生命周期最重要的 3 个方法,按照顺序依次是 init() 方法、service() 方法和 destroy() 方法。1) init()方法
init() 是 HttpServlet 类中的方法,可以在 Servlet 类中重写这个方法。init() 方法的声明格式如下:
public void init(ServletConfig config) throws ServletExceptionServlet 对象第一次被请求加载时,服务器创建一个 Servlet 对象,这个对象调用 init() 方法完成必要的初始化工作。该方法在执行时,服务器会把一个 ServletConfig 类型的对象传递给 init() 方法,这个对象就被保存在 Servlet 对象中,直到 Servlet 对象被销毁。
这个 ServletConfig 对象负责向 Servlet 传递服务设置信息,如果传递失败就会发生 ServletException 异常,Servlet 对象就不能正常工作。init() 方法只被调用一次,即在 Servlet 第一次被请求加载时调用该方法。
2) service()方法
该方法是 HttpServlet 类中的方法,可以在 Servlet 类中直接继承该方法或重写该方法。service() 方法的声明格式如下:public void service(HttpServletRequest request,HttpServletResponse response) throw ServletException,IOException当 Servlet 对象成功创建和初始化之后,该对象就调用 service() 方法来处理用户的请求并返回响应。
服务器将两个对象传递给该方法:
- 一个是 HttpServletRequest 类型的对象,该对象封装了用户的请求信息;
- 另外一个是 HttpServletResponse 类型的对象,用来响应用户的请求。
和 init() 方法不同的是,service() 方法可能被多次调用。我们已经知道,当后续的客户请求该 Servlet 对象服务时,服务器将启动一个新的线程,在该线程中,Servlet 对象调用 service() 方法响应客户的请求,也就是说,每个客户的每次请求都导致 service() 方法被调用,调用过程运行在不同的线程中,互不干扰。因此,不同线程的 service() 方法中的局部变量互不干扰,一个线程改变了自己的 service() 方法中局部变量的值不会影响其他线程的 service() 方法中的局部变量。
3) destroy()方法
当服务器关闭或 Web 应用被移除出容器时,Servlet 随着 Web 应用的销毁而销毁。在销毁 Servlet 之前,Servlet 容器会调用 Servlet的destroy() 方法,以便让 Servlet 对象释放它所占用的资源。在 Servlet 的整个生命周期中,destroy() 方法也只被调用一次。需要注意的是,Servlet 对象一旦创建就会驻留在内存中等待客户端的访问,直到服务器关闭,或 Web 应用被移除出容器时,Servlet 对象才会被销毁。
Servlet 的处理过程如下图所示:

图 2 Servlet的处理过程
Servlet技术的特点
JSP 和 Servlet 的区别到底在应用上有哪些体现,很多人搞不清楚。简单地说,Sun 公司首先开发出 Servlet,其功能比较强劲,体系设计也很先进,只是它输出 HTML 语句还是采用了旧的 CGI 方式,是一句一句地输出的,所以编写和修改 HTML 非常不方便。JSP 是一种实现普通静态 HTML 和动态 HTML 混合编码的技术,其并没有增加任何本质上不能用 Servlet 实现的功能。但是,在 JSP 中编写静态 HTML 更加方便,不必再用 println 语句来输出每一行 HTML 代码。
更重要的是,借助内容和外观的分离,页面制作中不同性质的任务可以方便地分开。比如,由页面设计者进行HTML设计,同时留出供Servlet程序员插入动态内容的空间。
既然 JSP 和 Servlet 都有自身的适用环境,那么能否扬长避短,让它们发挥各自的优势呢?答案是肯定的——模型-视图-控制器(Model-View-Controller,MVC)模式非常适合解决这一问题。
MVC 模式是软件工程中的一种软件架构模式,把软件系统分为 3 个基本部分,分别是模型(Model)、视图(View)和控制器(Controller):
- Model:业务功能编写(例如算法实现)、数据库设计以及数据存取操作实现;
- View:负责界面显示;
- Controller:负责转发请求,对请求进行处理。
在 JSP/Servlet 开发的软件系统中,这 3 个部分的描述如下图所示:

图 3 MVC模式
- Web 浏览器发送 HTTP 请求到服务器,被 Servlet 获取并进行处理(例如参数解析、请求转发);
- Controller(Servlet) 调用核心业务逻辑—— Model 部分,获得结果;
- Controller(Servlet) 将逻辑处理结果交给 JSP,动态输出 HTML 内容;
- 动态生成的 HTML 内容返回浏览器显示。
MVC 模式在 Web 开发中的好处非常明显,它规避了 JSP 与 Servlet 各自的短板,Servlet 只负责业务逻辑而不会通过 out.append() 动态生成 HTML 代码,在 JSP 中也不会充斥着大量的业务代码。这大大提高了代码的可读性和可维护性。
Servlet 程序在服务器运行,动态地生成 Web 页面。与传统的 CGI 技术相比,Servlet 具有高效率、易使用、功能强大、可移植性等特点。