Servlet生命周期

148 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第23天,点击查看活动详情

生命周期

Servlet的生命周期对应了三个方法:init()、service()、destroy()

当第一次接收请求时,servlet会进行实例化(调用构造方法)、初始化(调用init())、然后服务(调用service ()),最后当容器关闭时,其中的所有的servlet实例会被销毁,调用销毁方法(destroy()),当初始化过后每一次请求都会调用对应的service()方法

package com.sentiment.servlet;
​
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
​
public class Demo01 extends HttpServlet {
    public Demo01() {
        System.out.println("正在实例化.....");
    }
​
    @Override
    public void init() throws ServletException {
        System.out.println("正在初始化.....");
    }
​
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("正在启动服务.....");
    }
​
    @Override
    public void destroy() {
        System.out.println("正在销毁.....");
    }
}

当服务启动后 第一次发出请求时便会执行对应的构造器、init()、service()方法

而当服务关闭时则会执行destory()

初始化时机

默认情况下,实例化和初始化只会执行一次,这样做可以提高系统的启动速度,但如果我们需要提高响应速度则需设置一个参数

<load-on-startup>通过它可以设置servlet的启动顺序,数字越小启动越靠前,最小值为0

设置了该参数后,在启动环境时会默认进行实例化和初始化,避免了第一次请求后的实例化和初始化操作

线程安全问题

Servlet的线程安全问题 | Y4tacker's Blog

为了避免线程安全问题可采取:

①不要去修改成员变量的值

②不要去根据成员变量的值做一些逻辑判断

会话

HTTP无状态

看会话前先了解一下HTTP无状态

HTTP无状态:服务器无法判断这两次请求是同一个客户端发过来的,还是不同的客户端发过来的

会话跟踪技术

HTTP无状态会遇到一个问题︰第一次请求是添加商品到购物车,第二次请求是结账;如果这两次请求服务器无法区分是同一用户请求的

这时就要通过会话跟踪技术也就是seesion来解决

public class Demo02 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //服务器获取Session,如果没有则创建一个
        HttpSession session = req.getSession();
        System.out.println(session.getId());
    }
}

常用API

  • request.getsession () ->获取当前的会话,没有则创建一个新的会话
  • request.getsession (true) ->效果和不带参数相同
  • request.getsession (false)->获取当前会话,没有则返回null,不会创建新的
  • session.getId () ->获取sessionID
  • session.isNew ( ) ->判断当前session是否是新的
  • session.getMaxInactiveInterval () -> session的非激活间隔时长,默认1800秒session.setMaxInactiveInterval ()
  • session.invalidate () ->强制性让会话立即失效
  • getSession().setAttribute() -> 设置session
  • getSession().getAttribute() -> 获取seesion值

服务器端转发和客户端重定向

服务器内部转发

一次请求响应的过程,对于有客户端而言,内部经过了多少次转发,客户端是不知道的

地址栏没有变化

req.getRequestDispatcher("test6").forward(req,resp);

客户端重定向

两次请求响应的过程。客户端肯定知道请求URL有变化

地址栏有变化

resp.sendRedirect("test6");

Demo05

public class Demo05 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("demo05......");
        //req.getRequestDispatcher("test6").forward(req,resp);
        resp.sendRedirect("test6");
    }
}

Demo06

public class Demo06 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("demo06......");
    }
}

当启动服务访问test5后,若使用的是服务端转发,则url不变,但是会跳转到demo06输出demo06......

当使用客户端重定向后,url会随之从test5变为test6并输出demo06.........