大家好,我是勾玉!
该问来自2021届阅文Java方向笔试卷,servlet想必大家都有所了解,这是一个非常重要的知识点,希望大家多多关注。
servlet的生命周期可分为初始化、响应请求、终止三个阶段,下面我们对每个阶段做个分析。
1、初始化阶段
该阶段,下面三种情况下,servlet首先会被装载到servlet容器里:
1)Servlet容器启动时自动装载某些Servlet,实现它只需要在web.XML文件中的之间添加如下代码:
2)在Servlet容器启动后,客户首次向Servlet发送请求
3)Servlet类文件被更新后,重新装载Servlet
成功加载后,容器创建Servlet的实例,实例化之后,容器将调用Servlet的init()方法初始化这个对象。初始化的目的是为了让Servlet对象在处理客户端请求前完成一些初始化的工作,如建立数据库的连接,获取配置信息等:
public void init() throws ServletException { // 初始化代码...}
在Servlet的整个生命周期内,init()方法只被调用一次。
2、请求响应阶段
对于用户到达Servlet的请求,Servlet容器会创建特定于这个请求的ServletRequest对象和ServletResponse对象,然后调用Servlet的service方法,service() 方法是执行实际任务的主要方法。在service()方法中,Servlet实例通过ServletRequest对象得到客户端的相关信息和请求信息,在对请求进行处理后,调用ServletResponse对象的方法设置响应信息。
要注意的是,在service()方法调用之前,init()方法必须成功执行。
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException{}
对于Tomcat来说,它会将传递过来的参数放在一个Hashtable中,该Hashtable的定义是:
private Hashtable paramHashStringArray = new Hashtable();
这是一个String-->String[]的键值映射。HashMap线程不安全的,Hashtable线程安全。
3、终止阶段
当容器检测到一个Servlet实例应该从服务中被移除的时候,容器就会调用实例的destroy()方法,以便让该实例可以释放它所使用的资源,保存数据到持久存储设备中。当需要释放内存或者容器关闭时,容器就会调用Servlet实例的destroy()方法。在destroy()方法调用之后,容器会释放这个Servlet实例,该实例随后会被Java的垃圾收集器所回收。如果再次需要这个Servlet处理请求,Servlet容器会创建一个新的Servlet实例。
在整个Servlet的生命周期过程中,创建Servlet实例、调用实例的init()和destroy()方法都只进行一次,当初始化完成后,Servlet容器会将该实例保存在内存中,通过调用它的service()方法,为接收到的请求服务。
public void destroy() {// 终止化代码... }
Tomcat与Servlet的工作流程:
Web Client 向Servlet容器(Tomcat)发出Http请求
Servlet容器接收Web Client的请求
Servlet容器创建一个HttpRequest对象,将Web Client请求的信息封装到这个对象中。
Servlet容器创建一个HttpResponse对象
Servlet容器调用HttpServlet对象的service方法,把HttpRequest对象与HttpResponse对象作为参数传给 HttpServlet 对象。
HttpServlet调用HttpRequest对象的有关方法,获取Http请求信息。
HttpServlet调用HttpResponse对象的有关方法,生成响应数据。
Servlet容器把HttpServlet的响应结果传给Web Client。
除此之外,我们再谈谈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。
doGet方法示例:
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// Servlet 代码}
doPost方法示例:
public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// Servlet 代码}