深入理解servlet

深入理解servlet

web项目目录结构

webapp

  • static:静态资源
  • WEB-INF:Tomcat无法访问此目录
    • classes:字节码文件(后端java代码)
    • lib:项目依赖类库
    • web.xml:核心web配置,后端代码的入口

静态资源和动态资源的区别

  • 静态资源每次访问源代码不会发生改变

  • 动态资源每次访问代码都有可能会发生改变

    • servlet其实就是动态资源开发技术(Java)

      继承HttpServlet

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      /**
      * @description 接收get请求
      * @param req
      * @param resp
      * @return void
      * @author zhuweitung
      * @date 2020/9/14
      */
      public class HelloServlet extends HttpServlet {
      @Override
      protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
      resp.getWriter().write("hello servlet, " + DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
      }
      }

      web.xml中配置

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      <servlet>
      <!--servlet自定义名称-->
      <servlet-name>HelloServlet</servlet-name>
      <!--servlet对应类路径-->
      <servlet-class>com.zhuweitung.servlet.HelloServlet</servlet-class>
      </servlet>

      <!--servlet路径映射-->
      <servlet-mapping>
      <servlet-name>HelloServlet</servlet-name>
      <!--对外暴露的地址-->
      <url-pattern>/hello</url-pattern>
      </servlet-mapping>

      或使用注解@WebServlet

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      @WebServlet("/hello2")
      public class HelloServlet2 extends HttpServlet {

      /**
      * @description 接收get请求
      * @param req
      * @param resp
      * @return void
      * @author zhuweitung
      * @date 2020/9/14
      */
      @Override
      protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
      resp.getWriter().write("hello servlet, " + DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
      }
      }

servlet的生命周期

  • init():只会执行一次,执行初始化操作
  • service():处理请求,执行doGet或doPost
  • destroy():只执行一次,执行销毁操作

servlet只会初始化一次,多个请求同时访问servlet时只会实例化一次,即**servlet是单例(懒汉式)**的。

证明:由于servlet是通过xml配置文件或注解来生成的,所以是通过反射并调用servlet实现类的无参构造实例化的,只要在无参构造函数中输出即可证明

servlet自动加载

由于servlet是懒汉式单例模式的,当有请求时servlet才会被实例化,若要实现自动加载可以使用一下方法:

  • 在xml中配置load-on-startup

    1
    2
    3
    4
    5
    6
    7
    8
    <servlet>
    <!--servlet自定义名称-->
    <servlet-name>HelloServlet</servlet-name>
    <!--servlet对应类路径-->
    <servlet-class>com.zhuweitung.servlet.HelloServlet</servlet-class>
    <!--自动加载-->
    <load-on-startup>1</load-on-startup>
    </servlet>
  • 在注解@WebServlet中加上loadOnStartup = 1

    1
    @WebServlet(value = "/hello2", loadOnStartup = 1)

servlet线程不安全

证明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 共享变量
*/
private int count = 1;

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("HelloServlet2 doGet");
resp.getWriter().write("hello servlet, 第" + count + "次访问");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
}

两个浏览器进行访问,结果都显示第一次访问。

加锁解决线程安全问题。

注:使用servlet时不要使用共享全局变量。

servlet上下文

ServletContext也叫做“公共区域”,在同一个WEB应用程序中,所有的Servlet和JSP都可以共享同一个区域。

ServletContext在WEB服务器启动时创建,服务器关闭时销毁。

转发与重定向

转发

1
2
3
4
5
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setAttribute("username", "forward");
req.getRequestDispatcher("/test").forward(req, resp);
}

转发的特点:

  • 地址栏不发生变化
  • 只有一次请求
  • 转发地址中不需要加上下文地址
  • 请求域中的数据不会丢失
  • 是服务端行为
  • 效率高

重定向

1
2
3
4
5
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setAttribute("username", "redirect");
resp.sendRedirect("/test");
}

重定向的特点

  • 地址栏中地址变为重定向后的地址
  • 请求两次(客户端第一次请求后响应302状态,再请求重定向地址)
  • 重定向地址中需要加上下文地址以保证路径的正确
  • 请求域中的数据丢失
  • 是客户端行为
  • 效率低

深入理解servlet
https://blog.kedr.cc/posts/3236163550/
作者
zhuweitung
发布于
2020年9月14日
许可协议