Servlet
一、什么是servlet ?
Servlet本质上就是一个Java语言定义的接口,广义的Servlet就是指实现了这个Servlet接口的类。一般指的就是后者。
Servlet实例的主要功能就是根据客户端的请求,找到并调用服务端相关java代码,完成对请求的处理和运算。
Servlet实例遵循了服务器能够识别的规则,服务器会根据请求调用对应的servlet进行请求处理。
(1)Servlet实例,由Servlet容器创建,通常这个容器就是tomcat。
(2)Servlet是一个接口:位于javax.servlet包中。
二.HttpServlet
现在我们的请求都是基于HTTP协议的,所以应该专门为HTTP请求写一个Servlet做为通用父类。
HttpServlet的工作流程如下:
-
1.Web客户向Servlet容器发出Http请求
-
2.Servlet容器解析Web客户的Http请求
-
3.Servlet容器创建一个HttpRequest对象,在这个对象中封装Http请求信息
-
4.Servlet容器创建一个HttpResponse对象
-
5.Servlet容器调用HttpServlet的service方法,把HttpRequest和HttpResponse对象作为service方法的参数传给HttpServlet对象,service()方法会判断来自客服端的请求方式,根据不同请求方式调用不同方法,如果是get请求,则调用doGet()方法,如果是post请求,则调用doPost()方法
-
6.HttpServlet调用HttpRequest的有关方法,获取HTTP请求信息
-
7.HttpServlet调用HttpResponse的有关方法,生成响应数据
-
8.Servlet容器把HttpServlet的响应结果传给Web客户
三、使用HttpServlet实现http业务
步骤如下:
-
创建普通的java类,并继承HttpServlet接口
public class Servlet01 extends HttpServlet {}
-
重写service方法或doGet(),doPost()方法,添加业务逻辑代码
public class Servlet01 extends HttpServlet { //构造方法,Servlet被创建的时候调用 public Servlet01() { System.out.println("Servlet01--Servlet01"); } //get请求时调用的方法 @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 处理GET请求的逻辑 System.out.println("Servlet01--doGet"); } //Servlet实例化后,初始化后调用的方法, //当前类没有重写service方法则会调用父类,然后调用对应的doGet,doPost方法 @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("Servlet01--service"); } //Servlet创建之后调用的初始化方法 @Override public void init() throws ServletException { System.out.println("Servlet01--init"); } //销毁方法,Servlet被销毁时调用 @Override public void destroy() { System.out.println("Servlet01--destroy"); } }
-
在webRoot下的WEB-INF文件夹下的web.xml中配置Servlet及其映射,或者是使用@WebServlet注解
第一种, <servlet-name>是指servlet的名称,<servlet>标签和<servlet-mapping>标签中的<servlet-name>必须一致。<servlet-class>是当前servlet的全限定类名,<url-pattern>是映射servlet的url。
第二种,@webServlet注解里填地址即可
四、Servlet生命周期
Servlet生命周期是指servlet实例的初始化、服务执行、销毁的整个过程。
这些流程都是web服务器负责调用执行,程序员无法控制整个流程,但是程序员可以获取到这些Servlet生命周期的时间点,在这些时间点上可以做些业务相关的操作。
理解Servlet的生命周期还要看下Servlet的源码,源码中对其生命周期中的主要节点都有相应的方法:
整个方法调用的流程图如下:
当一个客户端请求过来的时候,tomcat服务器首先解析这个url,首先找到对应的应用app,然后根据/xxx去web.xml中根据配置信息去找对应的servlet,找到对应的servlet后,若还没有创建servlet实例就会新建一个该servlet实例,然后执行init()方法,service()方法,然后响应客户端;若该servlet实例已存在,就只会执行service()方法。当应用卸载的时候,会执行destory()方法销毁这个servlet实例。
总结一下servlet的特征:
-
servlet默认情况下是单例的,单例是指servlet的实例只有一个,每次客户端的请求,web服务器都会从servle容器中取出同一个Servlet实例,但是如果Servlet实现了SingleThreadModel接口,该Servlet对象在第一次线程阻塞时会创建新的对象,此时Servlet是多例的,有多个Servlet实例 -- 已过时。
-
默认情况下,servlet不会在服务启动时实例化,即一个servlet实例的无参构造和初始化也只会执行一次,且不会在服务启动时执行,而是在第一次请求时执行,所以接到请求时会先检查servlet实例是否已经存在
-
每次请求只会执行一个service方法,没有重写service方法则会调用父类的service方法,然后进而调用对应的doGet方法,doPost方法
-
一个servlet实例只会在服务停止时调用一次该方法
五:Servlet与线程安全
因为一个类型的Servlet默认只有一个实例对象,那么就有可能会现时出一个Servlet同时处理多个请求,所以Servlet是否为线程安全的呢?答案是:“不是线程安全的”。这说明Servlet的工作效率很高,但也存在线程安全问题!
所以我们不应该在Servlet中随便创建成员变量,因为可能会存在一个线程对这个成员变量进行写操作,另一个线程对这个成员变量进行读操作。
-
1.不要在Servlet中创建成员!创建局部变量即可!
-
2.可以创建无状态成员!无状态表示不可变
-
3.可以创建有状态的成员,但状态必须为只读的!