web笔记四:认识Servlet

本文详细介绍了Servlet的生命周期,包括初始化、服务和销毁三个阶段,解释了ServletConfig和ServletContext的作用及区别,并阐述了servlet-mapping的工作原理及其匹配规则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在了解Servlet之前,我们首先需要知道Servlet的生命周期,Servlet的生命周期分为三个阶段:
1. init
2. service
3. destroy
一个Servlet一生只实例化一次(除非实现了SingleThreadModel,该api在2.4已经被标记为@deprecated),只会调用一次init和destroy,所以servlet是单例多线程

了解Servlet需要知道的知识点:
1. servlet三个生命周期方法在什么时候执行
2. ServletConfig和ServletContext的是什么
3. 什么是servlet-mapping,规则是什么

一、Servlet三个生命周期方法在什么时候执行

  1. 初始化init方法会在服务器启动时或者第一次请求到来时执行,这取决于web.xml是否设置<load-on-startup>1</load-on-startup>,只要设置了loadOnStartup并且值大于0,那么该servlet将会在服务器启动完成之前完成初始化。
  2. service方法会在客户端请求对应的url-mapping时调用,容器会将请求信息封装成一个HttpServletRequest,将输出信息封装成一个HttpServletResponse,然后作为参数传递到service方法中。
  3. destroy方法将会在服务器停止时调用。

那么,这三个生命周期方法有什么作用呢?init方法通常做一些初始化的操作,比如数据库连接,init方法中会得到一个ServletConfig,可通过ServletConfig.getInitParameter(name)拿到初始化的值来进行初始化工作,当然,你也可以直接定义局部变量进行初始化工作(除非你确定该变量不会变动,否则尽量通过配置ServletConfig InitParameter的方式,方便维护)。service方法是用来响应客户端请求输出内容返回到客户端的,一般来说,我们更倾向于重写doGet和doPost请求来响应不同请求方式,一个请求只会执行一个Servlet。destroy主要用于一些资源释放的操作。

二、ServletConfig和ServletContext的是什么
上面我们提到了ServletConfig,那么什么是ServletConfig,怎么配置InitParameter,和ServletContext有什么区别?
ServletConfig是一个作用域仅限于当前Servlet的容器,而ServletContext能被所有Servlet共享。

对于ServletConfig来说,配置InitParameter只能在web.xml中的webapp.servlet.init-param进行配置,它没有对应的setXXX方法来设置参数。简单的配置如下:

<servlet>
    <servlet-name>MyServlet</servlet-name>
    <servlet-class>com.hxl.MyServlet</servlet-class>
    <init-param>
        <param-name>name</param-name>
        <param-value>hxl</param-value>
    </init-param>
    <init-param>
        <param-name>date</param-name>
        <param-value>2018</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

我们在Java程序中以下代码可以得到配置的参数值

public void init(ServletConfig config) throws ServletException {
    Enumeration<?> names = config.getInitParameterNames();
    while(names.hasMoreElements()) {
        String key = (String) names.nextElement();
        System.out.println(key+":"+config.getInitParameter(key));
    }
}

打印如下:

date:2018
name:hxl

对于ServletContext来说,可以通过webapp.context-param配置InitParameter,除了InitParameter,ServletContext还可以通过setAttribute的方式设置属性,任何Servlet都可以通过getAttribute拿到该属性,所以,attribute的使用需要谨慎小心,因为可能会存在并发的问题。记住,ServletContext是所有Servlet共享的

xml配置InitParameter:

<context-param>
    <param-name>sql</param-name>
    <param-value>mysql</param-value>
</context-param>

Java代码获取初始化参数,设置属性

ServletContext servletContext = config.getServletContext();
//获取InitParameter
String parameter = servletContext.getInitParameter("sql");
System.out.println(parameter);
//设置属性,记录请求数
servletContext.setAttribute(TOTAL_REQUEST, 0);
ServletContext servletContext = request.getSession().getServletContext();
//忽略并发代码...
int total =Integer.parseInt(servletContext.getAttribute(TOTAL_REQUEST)+"");
System.out.println("totalRequest:"+(total+1));
servletContext.setAttribute(TOTAL_REQUEST, total+1);

这样,当我们每请求一次,totalRequest就会+1

totalRequest:1
totalRequest:2
totalRequest:3

三、什么是servlet-mapping,规则是什么
servlet-mapping是用于将客户端请求映射到指定的servlet,匹配的规则如下:
1. Map exact URL–精确匹配
2. Map wildcard paths–通配符匹配
3. Map extensions–扩展名匹配
4. Map to the default servlet–匹配到默认servlet
例如:
Servlet1 映射到 /abc/*
Servlet2 映射到 /*
Servlet3 映射到 /abc
Servlet4 映射到 *.do

当请求URL为“/abc/a.html”,调用Servlet1。
当请求URL为“/abc”时,调用Servlet3。
当请求URL为“/abc/a.do”时,调用Servlet1。
当请求URL为“/a.do”时,调用Servlet2。
当请求URL为“/xxx/yyy/a.do”时,调用Servlet2。

我们一般都知道匹配规则的前三条,少部分人不知道第四条的default servlet是什么,了解default servlet之前,我们先了解<url-pattern>/</url-pattern><url-pattern>/*</url-pattern>的区别。

1、如果我们写的servlet(我们起类名为MyServlet)使用的url-pattern是/*,那么会响应一切url请求,就没有default servlet什么事了。

2、如果使用的是/,那么当我们请求的路径是.jsp为后缀的时候(这种情况下也仅仅能处理.jsp结尾的url),该请求不再经过MyServlet,而是匹配到default servlet。例如请求的是/abc/index.jsp,那么服务器会去abc文件夹(与WEB-INF文件夹同级)下查找index.jsp文件,如果请求/WEB-INF/index.jsp,即使存在该jsp,也请求不到任何资源,因为WEB-INF文件夹里的文件是受保护的。

3、如果使用的是/app/*,那么任何不匹配/app/*的url都将匹配到default servlet,服务器会将该url当成是静态资源文件路径去查找相应的文件信息。这估计是最有效处理静态资源的方式了。


最后,附上Servlet和web.xml的代码

import java.io.IOException;
import java.util.Enumeration;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyServlet extends HttpServlet {
    private static final String TOTAL_REQUEST="totalRequest";
    @Override
    public void init(ServletConfig config) throws ServletException {
        Enumeration<?> names = config.getInitParameterNames();
        while(names.hasMoreElements()) {
            String key = (String) names.nextElement();
            System.out.println(key+":"+config.getInitParameter(key));
        }

        ServletContext servletContext = config.getServletContext();
        //获取InitParameter
        String parameter = servletContext.getInitParameter("sql");
        System.out.println(parameter);
        //设置属性,记录请求数
        servletContext.setAttribute(TOTAL_REQUEST, 0);
    }

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ServletContext servletContext = request.getSession().getServletContext();
        //忽略并发代码...
        int total =Integer.parseInt(servletContext.getAttribute(TOTAL_REQUEST)+"");
        System.out.println("totalRequest:"+(total+1));
        servletContext.setAttribute(TOTAL_REQUEST, total+1);
    }
    @Override
    public void destroy() {
    }

}
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    id="cyt" version="3.0">
    <welcomefiles>
        <welcomefile>/index.jsp</welcomefile>
    </welcomefiles>
    <context-param>
        <param-name>sql</param-name>
        <param-value>mysql</param-value>
    </context-param>
    <servlet>
        <servlet-name>MyServlet</servlet-name>
        <servlet-class>com.hxl.MyServlet</servlet-class>
        <init-param>
            <param-name>name</param-name>
            <param-value>hxl</param-value>
        </init-param>
        <init-param>
            <param-name>date</param-name>
            <param-value>2018</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <!-- 这里不能设置为/*,否则default无效 -->
    <servlet-mapping>
        <servlet-name>MyServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    <!-- 默认servlet,用于处理js静态文件 
    Tomcat, Jetty, JBoss, and GlassFish 自带的默认Servlet的名字:"default"
    Google App Engine 自带的 默认Servlet的名字:"_ah_default"
    Resin 自带的 默认Servlet的名字:"resin-file"
    WebLogic 自带的 默认Servlet的名字:"FileServlet"
    WebSphere  自带的 默认Servlet的名字:"SimpleFileServlet" 
    -->
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.js</url-pattern>
    </servlet-mapping>
</web-app>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值