1、什么是servlet?
Servlet是Server和Applet的缩写,是服务端小程序的意思。使用Java语言编写的服务程序,可以生成动态的web页面,Servlet主要运行在服务器端,由服务器调用执行,是一种按照Servlet标准开发的类。
Servlet本质上也是java类,但要遵循Servlet规范进行编辑,没有main方法,它的创建、使用、销毁都是由Servlet容器进行管理(如Tomcat服务器)。
Servlet的几个特点:
-
Servlet是用于Java编写的Server端程序,它与协议和平台无关
-
Servlet运行与Java -enable Web Server中
-
Java Servlet可以动态地扩展Server的能力,并采用请求-响应模式提供web服务
-
最早支持Servlet技术的是JavaSoft的Java Web Server
-
一些其他的基于Java的Web Server开始支持标准的Servlet API
-
Servlet的主要功能在于交互式地浏览器修改数据,生成动态web内容
上面六点中,最需要被记住的是Servlet可以动态地扩展Server的能力,并采用请求-响应模式提供Web服务。
JDK中的Servlet是一个接口:
public interface Servlet {
public void init(ServletConfig config) throws ServletException;
public ServletConfig getServletConfig();
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;
public String getServletInfo();
public void destroy();
}
可以看到Servlet是一个接口,规定了请求从容器到达web服务端的规范,简单概括三个重要步骤:
-
init():初始化请求的时候要做什么?
-
service():拿到请求的时候要做什么?
-
destory():处理完请求销毁的时候要做什么?
所有的Servlet的实现都是在这个规范的基础上进行开发的,那么Servlet中的数据是从哪里来的,答案就是Servlet容器。容器才是真正与客户端打交道的那一方,一个容器中Servlet可以有多个,常见的Servlet容器Tomcat,它监听了客户端的请求端口,根据请求行信息确定将请求交给哪个Servlet处理,找到处理的Servlet之后,调用该Servlet的service()方法,处理完毕将对应的处理结果包装成ServletResponse对象返回给客户端
Servlet和http协议紧密联系,可以处理所有的http协议相关内容。通过下面的步骤可以了解http请求和响应的过程。
2、servlet与servlet容器的关系
Context容器
tomcat的容器等级中,context容器是直接管理servlet在容器中的包装类wrapper,context容器如何运行将直接影响servlet的工作方式。
由图可知,tomcat的底层是context,管理servlet容器的是context容器,一个context对应一个web工程,在tomcat配置文件中可以发现这一点:
<Context path="/projectOne" docBase="D:\路径" reloadable="true" />
Servlet如何工作?
当用户在浏览器向服务器发起一个请求,请求信息:
http://hostname: port /contextpath/servletpath
-
hostname和port是用来与服务器建立tcp连接
-
/contextpath/servletpath 即url用来选择服务器中哪个子容器来服务用户的请求
servlet生命周期
servlet的生命周期分为四部分:实例化==>初始化 ==>执行处理 ==> 销毁
实例化
new,服务器第一次被访问时,加载一个servlet容器,只会加载一次
初始化
init:创建完servlet容器后,会调用仅执行一次的init()初始化方法,用于初始化servlet对象,无论多少台客户端在服务器运行期间访问都不会再执行init()方法
继承GenericServlet抽象类中可以看初始化方法:
public void init() throws ServletException {
}
在servlet类中继承调用该方法:
public void init() throws ServletException {
super.init();
}
创建servlet对象的时机:
-
Servlet容器启动时,读取web.xml配置文件中的信息,构造指定的servlet对象,创建servlet对象,同时将ServletConfig对象作为参数来调用servlet对象的init方法。
-
在servlet容器启动后,客户首次向servlet发出请求,servlet容器会判断内存中是否存在指定的servlet对象,如果没有则创建它,根据客户的请求创建HttpRequest、HttpResponse对象,从而调用Servlet对象的service方法。
-
servlet servlet容器在启动时自动创建servlet,这是由web.xml文件中为servlet设置的< load-on-startup>属性决定的。可以看到同一个类型的servlet对象在servlet容器中以单例的形式存在。
执行处理
执行处理--service()方法
它是servlet的核心,负责响应客户的请求。每当一个客户请求一个HttpServlet对象,该对象的Service()方法就要调用,而且传递这个方法一个"请求"(ServletRequest)对象和一个"响应"(ServletResponse)对象作为参数。在HttpServlet中已存在Service()方法。默认的服务功能是调用与HTTP请求的方法对应的do功能。
HttpServlet的抽象类提供了doGet()、doPost()...等方法,对应request请求的发送方法,与之相匹配:
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_get_not_supported");
if (protocol.endsWith("1.1")) {
resp.sendError(405, msg);
} else {
resp.sendError(400, msg);
}
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_post_not_supported");
if (protocol.endsWith("1.1")) {
resp.sendError(405, msg);
} else {
resp.sendError(400, msg);
}
}
销毁
销毁--destroy:在服务器关闭或重启时,Servlet会调用destory方法来销毁,将Servlet容器标记为垃圾文件,让GC做回收处理,在编写的Servlet调用了GenericServlet抽象;类的destroy方法:
@Override
public void destroy() {
super.destroy();
}
Servlet工作原理
-
简单解释一下servlet接收和响应客户请求的过程:
客户发送一个请求,Servlet是调用service()方法对请求进行响应,service()方法中对请求的方式进行了匹配。选择调用doGet()、doPost()等方法,然后进入对应的方法中调用逻辑层方法,实现对客户的响应。Servlet接口和GenericServlet中是没有doGet()、doPost()这些方法的。HttpServlet中定义了这些方法,凡是都是返回error信息,所以每定义一个Servlet的时候,都必须实现doGet()或doPost()方法。
-
每一个自定义的Servlet都必须实现Servlet的接口,Servlet接口中定义了五个方法,其中比较重要的三个方法涉及到了Servlet的生命周期,分别是init()、service()、destroy()方法,GenericServlet是一个通用的,不特定于任何协议的Servlet,它实现了Servlet接口。而HttpServlet继承与GenericServlet,因此HttpServlet实现了Servlet接口,定义Servlet的时候继承HttpServlet即可。
-
Servlet接口和GenericServlet是不特定于任何协议的,而HttpServlet是特点于HTTP协议的类,在HttpServlet中实现了service()方法,将请求ServletRequest、ServletResponse强转为HttpRequest和HttpResponse。
-
servlet是单例模式,线程不安全,在service()方法中尽量不要操作全局变量,实际上,可以通过使用session和application来代替全局变量,只是会加大服务器负载。
Servlet处理请求的过程
-
客户端发送请求给服务器
-
容器根据请求即web.xml判断对应的Servlet是否存在,如果不存在则返回404
-
容器根据请求即web.xml判断对应的Servlet是否已经被实例化,若是响应的Servlet没有被实例化,则容器将会加载相应的Servlet到Java虚拟机并实例化
-
调用实例对象的service()方法,并开启一个新的线程去执行相关处理,调用service方法,判断是调用doGet方法还是doPost方法
-
业务完成后响应相关的页面发送给客户端
3、tomcat和servlet的关系
Tomcat是web应用服务器,是一个Servlet/jsp容器。tomcat作为servlet容器,负责处理客户请求,把请求传送给servlet,将servlet的响应传回给客户,而servlet是一个Java应用程序,运行在服务器,处理客户端请求并作出响应的程序,servlet最常见的用途是扩展java web服务器功能,提供非常安全的,可移植的,易于使用的CGI替代品。
从http协议中的请求和响应可以得知,浏览器发出的请求是一个请求文本,而浏览器接收到的应该也是一个响应文本,在上面那个图中,并不知道是如何转变的,只知道浏览器发送过来的请求也就是request,响应回去的就用response。
-
Tomcat将http请求文本接收并解析,封装成HttpServletRequest类型的request对象,所有的HTTP头数据读可以通过request对象调用对应的方法查询到
-
Tomcat同时会响应的信息封装为HttpServletResponse类型的response对象,通过设置response属性就可以控制要输出到浏览器的内容,然后将response交给tomcat,tomcat就会将其变成响应文本的格式发送给浏览器
-
Java Servlet API是Servlet容器(tomcat)和Servlet之间的接口,它定义了servlet的各种方法,还定义了Servlet容器传送给Servlet的对象类,其中最重要的就是ServletRequest和ServletResponse,在编写Servlet时需要实现Servlet接口,按照其规范进行操作。
HttpServletRequest概述
javax.servlet.http.HttpServletRequest是SUN制定的Servlet规范,是一个接口,表示请求, 其父接口是 javax.servlet.ServletRequest。“ HTTP 请求协议”的完整内容都被封装到 request对象中。
请求的生命周期
Http ServletRequest 实例对象是什么时候创建和销毁的呢?
当客户端浏览器将请求(字符序列)发送到服务器后,服务器会根据HTTP请求协议的格式对请求进行解析。同时,服务器会创建HttpServletRequest的实现类RequestFacade的对象,即请求对象。再调用相应的set方法,将解析出的数据封装到请求对象中,此时HttpServletRequest实例就创建并初始化完毕了。也就是说,请求对象是由服务器创建。
当服务器向客户端发送响应结束后,HttpServletRequest实例对象被服务器销毁。
一次请求对应一个请求对象,另外一次请求对应另外一个请求对象,与之前的请求对象没有任何关系,HttpServletRequest实例的生命周期很短暂。