servlet学习笔记(2):servlet的体系结构

1.整体结构

在这里插入图片描述

2.常用方法

2.1Servlet常用方法

  • void init(ServletConfig config):初始化
  • void service(ServletRequest request, ServletResponse response):服务 处理业务逻辑
  • void destroy():销毁
  • ServletConfig getServletConfig() :获取当前servlet的配置对象

2.2 GenericServlet常用方法

  • 除了service方法没有具体实现,其余都实现了
  • 空参的Init() 若我们自己想对servlet进行初始化操作,重写这个init()方法即可
  • 查看该init()方法的源码
    • 1.进入HttpServlet
      在这里插入图片描述
      在这里插入图片描述
    • 2.进入 GenericServlet
      在这里插入图片描述
    • 3.找到init方法
      在这里插入图片描述

2.3HttpServlet常用方法

  • service做了实现,把参数进行强制转换,调用了重载的service方法

  • 重载的servide方法获取请求的方式,根据请求的不同调用相应的doGet()/doPost()方法

  • 查看源码

    在这里插入图片描述

  • public void service(ServletRequest req, ServletResponse res)

      public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
            HttpServletRequest request;
            HttpServletResponse response;
            try {
            	//强转
                request = (HttpServletRequest)req;
                response = (HttpServletResponse)res;
            } catch (ClassCastException var6) {
                throw new ServletException("non-HTTP request or response");
            }
    		//调用这个重载的方法
            this.service(request, response);
        }
    

-注意参数类型

  • 进入重载的service
    在这里插入图片描述
  • protected void service(HttpServletRequest req, HttpServletResponse resp)
  • 注意参数类型
  • 先获取请求的方法GET/POST
  • 然后根据方法做判断
  protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getMethod();
        long lastModified;
        if (method.equals("GET")) {
            lastModified = this.getLastModified(req);
            if (lastModified == -1L) {
                this.doGet(req, resp);
            } else {
                long ifModifiedSince;
                try {
                    ifModifiedSince = req.getDateHeader("If-Modified-Since");
                } catch (IllegalArgumentException var9) {
                    ifModifiedSince = -1L;
                }

                if (ifModifiedSince < lastModified / 1000L * 1000L) {
                    this.maybeSetLastModified(resp, lastModified);
                    this.doGet(req, resp);
                } else {
                    resp.setStatus(304);
                }
            }
        } else if (method.equals("HEAD")) {
            lastModified = this.getLastModified(req);
            this.maybeSetLastModified(resp, lastModified);
            this.doHead(req, resp);
        } else if (method.equals("POST")) {
            this.doPost(req, resp);
        } else if (method.equals("PUT")) {
            this.doPut(req, resp);
        } else if (method.equals("DELETE")) {
            this.doDelete(req, resp);
        } else if (method.equals("OPTIONS")) {
            this.doOptions(req, resp);
        } else if (method.equals("TRACE")) {
            this.doTrace(req, resp);
        } else {
            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[]{method};
            errMsg = MessageFormat.format(errMsg, errArgs);
            resp.sendError(501, errMsg);
        }

    }

3.Servlet生命周期(重要)

定义一个类LifeServlet,继承Servlet接口,实现init(),service(),destroy()方法,来说明servlet的生命周期

3.1定义一个类LifeServlet

	package com.zqx.c_life;

import javax.servlet.*;
import java.io.IOException;

/**
 * 20190810
 * 实现Servlet接口
 * 说明 Servlet的生命周期
 */
public class LifeServlet implements Servlet {


    /**
     * 初始化方法
     * 执行者:服务器
     * 执行次数:一次
     * 执行时机:默认第一次访问的时候
     */
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("5555555555555555");
    }
    /**
     * 服务
     * 执行者:服务器
     * 执行次数:请求一次执行一次
     * 执行时机:请求来的时候
     */
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("666666666666666");
    }
    /**
     * 销毁
     * 执行者:服务器
     * 执行次数:只执行一次
     * 执行时机:当servlet被移除的时候或者服务器正常关闭的时候
     */
    @Override
    public void destroy() {
        System.out.println("4444444444444444");

    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }



    @Override
    public String getServletInfo() {
        return null;
    }


}

3.2html页面

 <a href="/servlet/life?name=tom">生命周期</a>

3.3web.xml

 <servlet>
        <servlet-name>LifeServlet</servlet-name>
        <servlet-class>com.zqx.c_life.LifeServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>LifeServlet</servlet-name>
        <url-pattern>/life</url-pattern>
    </servlet-mapping>

3.4观察结果

在这里插入图片描述

3.5小结

void init(ServletConfig config):初始化

  • 初始化方法
  • 执行者:服务器
  • 执行次数:一次
  • 执行时机:默认(说明可以自己设置)第一次访问的时候
  • 只执行一次说明一个Servlet在内存中只存在一个对象,Servlet是单实例的
    • 当多个用户访问一个Servlet中的全局变量时,可能存在线程安全问题
    • 解决:尽量不要再Servlet中定义全局变量,即使定义了,也不要修改值,只对其访问即可

void service(ServletRequest request,ServletResponse response):服务 处理业务逻辑

  • 服务
  • 执行者:服务器
  • 执行次数:请求一次执行一次
  • 执行时机:请求来的时候

void destroy():销毁

  • 销毁
  • 执行者:服务器
  • 执行次数:只执行一次
  • 执行时机:当servlet被移除的时候或者服务器正常关闭的时候

servlet是单线程多实例,默认第一次访问的时候,服务器创建servlet,并调用init方法实现初始化,并调用一次service方法, 每当有新的请求,服务器创建一个线程,调用service方法来执行自己的业务逻辑,当当serlvet被移除的时候服务器正常关闭的时候,服务器调用servlet的destroy方法实现销毁操作.

4.url-pattern配置

创建一个servlet后,这个servlet要被访问到,必须在web.xml中进行配置,其中有一个<url-pattern>的标签确定访问一个servlet的路径

4.1一个servlet可以被多个路径映射

 <servlet>
        <servlet-name>LifeServlet</servlet-name>
        <servlet-class>com.zqx.c_life.LifeServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>LifeServlet</servlet-name>
        <url-pattern>/life</url-pattern>
    </servlet-mapping>
    <!--一个servlet可以被不同的路径映射-->
    <servlet-mapping>
        <servlet-name>LifeServlet</servlet-name>
        <url-pattern>/life01</url-pattern>
    </servlet-mapping>
  • 上述例子说明com.zqx.c_life.LifeServlet可以被路径/life/life01访问到

4.2的三种写法

  • 完全匹配:必须以”/”开始,例如: /hello /a/b/c
  • 目录匹配:必须"/"开始 以"*"结束 例如: /a/* /*
  • 后缀名匹配 以"*"开始 以字符结尾 例如: *.jsp *.do *.action
  • 优先级:完全匹配>目录匹配>后缀名匹配

4.3测试

假设:

  • Servlet1 映射到 /abc/*
  • Servlet2 映射到 /*
  • Servlet3 映射到 /abc
  • Servlet4 映射到 *.do
    问:
  • 当请求URL为“/abc/a.html”,“/abc/”和“/”都匹配,哪个servlet响应
    • 完全匹配>目录匹配
    • Servlet引擎将调用Servlet1。
  • 当请求URL为“/abc”时,“/*”和“/abc”都匹配,哪个servlet响应
    • 完全匹配 > 目录匹配
    • Servlet引擎将调用Servlet3。
  • 当请求URL为“/abc/a.do”时,“/abc/”和“.do”都匹配,哪个servlet响应
    • 目录匹配> 后缀匹配
    • Servlet引擎将调用Servlet1。
  • 当请求URL为“/a.do”时,“/”和“.do”都匹配,哪个servlet响应
    • 目录匹配>后缀匹配
    • Servlet引擎将调用Servlet2.
  • 当请求URL为“/xxx/yyy/a.do”时,“/”和“.do”都匹配,哪个servlet响应
    • 目录匹配>后缀匹配
    • Servlet引擎将调用Servlet2。

4.4tomcat中的tomcat/conf/web.xml

 <servlet-mapping>
        <servlet-name>jsp</servlet-name>
        <url-pattern>*.jsp</url-pattern>
        <url-pattern>*.jspx</url-pattern>
    </servlet-mapping>
  • 只要访问时后缀名是jsp或jspx就会执行名称叫jsp的servlet内容,这是一个很典型的扩展名匹配效果
   <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
  • 这时<url-pattern>它的值就是”/”那么这时它就是一个默认(缺省)的servlet.。 默认的servlet其作用是用于处理其它的servlet处理不了的请求。

5.load-on-satrtup

前面说到一个servlet的生命周期的时候,init方法的执行时间是默认第一次访问的时候,通过对某个Servlet的配置,可以改变这个方法的执行时间

5.1基础

  • load-on-startup是servlet标签下的一个子标签
  • 用来修改servlet的初始化时间
  • 值为负数时,第一次访问时创建
  • 值为正整数,在服务器启动的时候就被创建,值越小优先级越高
  • 实例:
     <servlet>
        <servlet-name>LifeServlet</servlet-name>
        <servlet-class>com.zqx.c_life.LifeServlet</servlet-class>
        <load-on-startup>3</load-on-startup>
    </servlet>
    
  • 效果
    在这里插入图片描述
  • 可以看到,在服务器启动的时候,LifeServletinit方法就已经被调用了
  • 适用于在项目启动的时候,需要做一些初始化的操作,可以通过这样的方式来设置

5.2 tomcat中的web.xml

5.2.1访问项目里不存在的资源

  • 首先,一个有趣的例子,当我们在浏览器访问一个项目中没有进行配置过的路径
    在这里插入图片描述
    在这里插入图片描述
  • 虽然返回的是404,但是这个页面仍然是有内容的和响应消息,这个内容是谁发送到这里的呢?就是tomcat服务器
  • 那么这个过程是如何响应的呢?tomcat服务器是如何完成这个响应的呢?
  • 查看tomcat/conf/web.xml,发现有这一段配置信息:
 <servlet>
        <servlet-name>default</servlet-name>
        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <init-param>
            <param-name>listings</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
  <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
  • 访问一个路径的时候,当项目中的配置文件没有指定配置的时候,会查找tomcat的web.xml
  • 这说明项目中的web.xml和tomcat的web.xml直接存在一种继承关系,优先查找项目里的web.xml,如果没有找到,就会去tomcat的web.xml中查找

5.2.2访问index.html

  • 同样我们没有对index这个路径进行过配置吗,但是仍然访问可以出现页面
  • 这也是因为tomcat的web.xml配置文件帮助实现了配置
<welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

6.路径的写法

  • 相对路径
    • 当前路径:./ 或者 不写
    • 上一级路径:../
  • 绝对路径:
    • 带主机的和协议的绝对路径:
      • http://www.baidu.com
    • 不带主机和协议的绝对路径:
      • /servlet/hello经常使用
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值