浅析servlet底层

本文详细解析了servlet的概念、实现过程、可完成的任务及其特点,探讨了servlet与Tomcat的底层原理,包括servlet接口、生命周期及与GenericServlet、HttpServlet的关系。通过对servlet的深入理解,有助于提升Web应用开发的能力。

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

本文引导

学习原因

为了探讨tomcat底层原理

知识回顾

abstract:在java中是一个修饰词,意为抽象的,可以修饰类,方法,事件。抽象类是没有实例对象的类,抽象方法是没有方法体的方法。
throws:抛出异常关键字,出现在函数头,用于抛出异常,表示发生异常的一种可能性,并不一定会发生异常。常见的异常有IOException(输入输出流异常),NullpointException(空指针异常)。
extends:用来继承一个已有的类,被继承的类成为父类(超类,基类),java中不允许多继承。
implements:实现接口。一个类只能继承一个父类,但是可以实现多个接口。
ServletRequest、ServletResponse:由servlet容器管理,当用户请求时,容器创建一个ServletRequest对象封装请求数据,同时创建一个ServletResponse对象封装响应数据,这两个对象将被容器作为service()方法的参数传递给servlet,servlet利用ServletRequest对象获取客户端发送的请求数据,利用ServletResponse对象发送响应数据。
Cookie:小型文本文件,是某些网站为了辨别用户身份,进行Session跟踪而储存在用户本地终端上的数据,通常经过加密。

什么是servlet

servlet的定义

servlet(server applet)是java servlet的简称,是为小服务程序或服务连接器,用java编写的服务器端程序,主要功能在于交互式地浏览、修改数据,生成动态web内容。

A servlet is a small Java program that runs within a Web server. Servlets receive and respond to requests from Web clients, usually across HTTP, the HyperText Transfer Protocol. (servlet是一个运行在web服务器的java小程序,servlet接收并响应来自web客户端的请求,通常通过HTTP,超文本传输协议)

实现过程

1、客户端发送请求至服务器端
2、服务器发送请求至servlet
3、servlet生成响应内容并将其传给服务器,响应内容动态生成,通常取决于客户端的请求
4、服务器将响应返回给客户端

servlet可完成的任务

1、动态生成HTML文档
2、将请求转发给servlet组件
3、读取客户端的Cookie,以及向客户端写入Cookie
4、访问服务器的资源,如数据库、XML、文件对象等

servlet特点

1、servlet对象由容器(tomcat)创建
2、servlet是一个接口,位于javax.servlet包中
3、service方法用于接受用户请求并返回响应
4、用户访问时多次被执行(统计网站访问量)

servlet底层原理

1、javax.servlet Interface Servlet

package javax.servlet;
import java.io.IOException;
public abstract interface Servlet{
	public abstract void init(ServletConfig paramServletConfig)
	throws ServletException;
	public abstract ServletConfig getServletConfig();
	public abstract void service(ServletRequest paramServletRequest,ServletResponse paramServletResponse)
	throws ServletException,IOException;
	public abstract String getServletInfo();
	public abstract void destroy();
}
返回值方法描述
voiddestroy()由servlet容器调用,以指示servlet将被排除在服务之外(销毁)
servletconfiggetServletConfig()返回一个servletconfig对象,其中包含这个servlet的初始化和启动参数
java.lang.StringgetServletInfo()返回有关servlet的信息,如作者,版本,版权
voidinit(ServletConfig config)由servlet容器调用,以指示将servlety放入服务中的servlet
voidservice(ServletRequest req,ServletResponse res)由servlet容器调用,以允许servlet对请求做出响应

servlet、GenericServlet、HttpServlet的关系

继承
实现
实现
子类:HttpServlet
父类:GenericServlet
接口:Servlet
接口:ServletConfig

2、servlet实现方式

实现servlet接口

package cn.hncu;

import java.io.IOException;

import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class FirstServlet implements Servlet {
    /**init方法*/
    @Override
    public void init(ServletConfig paramServletConfig) throws ServletException {
    }

    /**getServletConfig方法*/
    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

/**service方法*/
    @Override
    public void service(ServletRequest paramServletRequest,
            ServletResponse paramServletResponse) throws ServletException,
            IOException {
    }

    /**getServletInfo方法*/
    @Override
    public String getServletInfo() {
        return null;
    }

    /**destroy方法*/
    @Override
    public void destroy() {
    }
}

继承GenericServlet类

package cn.hncu;

import java.io.IOException;

import javax.servlet.GenericServlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

/**【注意】GenericServlet是抽象类,service是抽象方法*/
public class ExtendGenericServlet extends GenericServlet {

    /**service方法*/
    /**【注意】唯独service方法没有被实现,这个service方法我们自己使用*/
    @Override
    public void service(ServletRequest paramServletRequest,
            ServletResponse paramServletResponse) throws ServletException,
            IOException {
    }
/**destroy方法*/
    /**【注意】除过service方法之外,其他方法都已经被实现了,并且这些方法都调用父接口的方法*/
    @Override
    public void destroy() {
        super.destroy();
    }

    /**getServletConfig方法*/
    @Override
    public ServletConfig getServletConfig() {
        return super.getServletConfig();
    }
    /**getServletInfo方法*/
    @Override
    public String getServletInfo() {
        return super.getServletInfo();
    }

    /**init方法*/
    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
    }

    /**【注意】:如果我们覆盖带参数的init父类方法时候,没有写super.init(config)这一句:
    public void init(ServletConfig config) throws ServletException {
    }
    我们的程序会出现空指针异常错误:
    严重: Servlet.service() for servlet [ExtendsGenericServlet] in context with path [/useServlet] threw exception
java.lang.NullPointerException
    at javax.servlet.GenericServlet.getInitParameterNames(GenericServlet.java:99)
    at cn.hncu.ExtendsGenericServlet.service(ExtendsGenericServlet.java:53)

    我们知道,此时getInitParameterNames是空指针,我们去API中查看,关于getInitParameterNames的来源,
    如果来源的某一地方是空指针,则就说明这个地方值为空!

    我们依次点击这些类的关联:

     public Enumeration<String> getInitParameterNames()
     {
         return getServletConfig().getInitParameterNames();
     }
     ----》说明:getServletConfig()为NULL

     public ServletConfig getServletConfig()
     {
         return this.config;
     }
     ----》说明:config为NULL

    public void init(ServletConfig config)
    throws ServletException
    {
       this.config = config;
       init();
    }
    ----》说明:此处就是问题的根源:config没有赋值

    ----》也说明:带参数的init方法没有被执行

    ----》因为我们在父类方法的时候,正好将父类的方法:init(config)给删除了

    ----》所以覆盖父类方法的时候这句一定要写!


//GenericServlet类中有一个空参init()方法,

//其实是适配器模式中的一个技术细节:在带参init方法中帮我们把config赋好值,

//然后调用空参且空实现init()方法--该方法是专门给子类覆盖的。

//---在适配器中帮我们做一部分事情,然后调用我们的覆盖方法

//该注释组转自博客园

}

继承HttpServlet类

package cn.hncu;


import java.io.IOException;

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

public class ExtendHttpServlet extends HttpServlet {

    /**service方法*/
    /**【注意】此service方法是HttpServlet类 继承 GenericServlet类 后实现的其抽象service方法的*/
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        super.service(req, resp);
    }
    /**destroy方法*/
    /**【注意】下面的这些方法全部是继承与GenericServlet类中的方法*/
    @Override
    public void destroy() {
        super.destroy();
    }

    /**getServletConfig方法*/
    @Override
    public ServletConfig getServletConfig() {
        return super.getServletConfig();
    }

    /**getServletInfo方法*/
    @Override
    public String getServletInfo() {
        return super.getServletInfo();
    }

    /**init方法*/
    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
    }
}

servlet生命周期

1、init()方法
只会被初始化一次,由容器初始化初始化成功后将缓存于容器中。
2、service()方法
每次请求都会访问次方法,每次请求都会创建新的Request、Response对象。
3、destory()方法
当服务器关闭时由容器调用并销毁

这里就不再写出生命周期测试代码,测试方法为依次重写五个方法为输出字符串,测试结果顺序为init、service、getServletConfig、getServletInfo、destory。

可修改配置文件web.xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
  <display-name></display-name>
  <servlet>
    <servlet-name>TestServlet</servlet-name>
    <servlet-class>cn.hncu.TestServlet</servlet-class>
    <!-- 
    在启动在启动时加载元件负载指示就加载这个servlet(实例化并调用其())对Web应用程序的启动。
    这些元素的可选内容必须是一个整数,指示应加载servlet的顺序。
    如果值是负整数,或者元素不存在,容器可以自由加载servlet。
    如果该值是正整数或0,则容器必须在部署应用程序时加载和初始化servlet。
    容器必须保证servlet标有低整数在servlet标有高整数装。
    容器可选择顺序加载Servlet具有相同的负载启动值。
     -->
    <load-on-startup>20</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>TestServlet</servlet-name>
    <url-pattern>/servlet/TestServlet</url-pattern>
  </servlet-mapping>    
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>

修改后执行结果:
执行结果
(图片引用自右下角水印处,侵权必删)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值