Servlet、GenericServlet和HttpServlet之间的关系

一、什么是Servlet

      在 JavaWeb 项目中,处理请求和发送响应的过程是由一种叫做 Servlet 的程序来完成的,并且 Servlet 是为了解决实现动态页面而衍生的东西。

    简单来讲:Servlet其实就是一个遵循Servlet开发的java类,Serlvet是由服务器调用的,运行在服务器端

     Servlet是JavaWeb的三大组件之一,它属于动态资源。其主要功能在于交互式的浏览和修改数据,生成动态Web内容。Servlet运行于支持Java的应用服务器中。Servlet的作用是处理请求,服务器会把接收到的请求交给Servlet来处理,在Servlet中通常需要完成三件事:   

   (1)接收请求数据;(2)处理请求;(3)完成响应。

例如:客户端发出登录请求或者注册请求,这些请求都应该由Servlet来完成处理!Servlet需要我们自己来编写。

区分Servlet和Servlet容器(举例Tomcat):

        子弹和枪的关系:枪为子弹而生,子弹让枪有了杀伤力

二、实现Servlet的方式

(1)实现javax.servlet.Servlet接口;
(2)继承javax.servlet.GenericServlet类;
(3)继承javax.servlet.http.HttpServlet类;通常我们会去继承HttpServlet类来完成我们的Servlet;

首先我们来看看Servlet GenericServlet和HttpServlet的关系

                      

可以看到,它们之间存中继承关系:假如现有我们自定义的一个Servlet,继承HttpServlet,那么实际上它的继承链如下图

                     

可以看到,核心的部分在于:

  • 两个顶级接口
    • Servlet
    • ServletConfig
  • 接口的实现类
    • GenericServlet
  • 基于HTTP协议的实现类
    • HttpServlet

看看这些核心部分主要有那些方法:

                    

                   

其中重点摘录部分进行说明:

  • Servlet接口的内容
public interface Servlet {
	void init(ServletConfig var1) throws ServletException;

	ServletConfig getServletConfig();

	void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;

	String getServletInfo();

	void destroy();
}

       从这里可以看到,Servlet生命周期的三个关键方法,init、service、destroy。还有另外两个方法,一个getServletConfig()方法来获取ServletConfig对象,ServletConfig对象可以获取到Servlet的一些信息。

  • ServletConfig  Servlet的配置信息,常用来在Servlet初始化时进行信息传递
    • getServletContext()  获取Servlet运行的上下文环境对象,可以获取对应信息(如Servlet路径),存取容量级的变量
    • getInitParameter(String name)  获取初始化参数(web.xml中配置的init-param)

先总结前两个:

         Servlet接口中的内容和作用,总结起来就是,三个生命周期运行的方法,获取ServletConfig,而通过ServletConfig又可以获取到ServletContext。

  • GenericServlet  一个抽象类,实现了Servlet和ServletConfig接口
    • init(ServletConfig config)  初始化方法,方法中调用了init()
    • init()  初始化方法,方法体为空,主要用于自定义Servlet的覆盖
    • service(ServletRequest request, ServletResponse response)  抽象方法service,要求继承类实现
    • destory()  Servlet销毁前要执行的方法

我们可以看到:

      GenericServlet实现了Servlet接口后,就可以使用Servlet接口中的那几个方法了,能拿到ServletConfig,也可以拿到ServletContext,不过那样太麻烦,不能直接获取ServletContext,所以GenericServlet除了实现Servlet接口外,还实现了ServletConfig接口,那样,就可以直接获取ServletContext了。

注意点:

1、上图我们观察到,init方法存在两个,一个带参,一个无参

private transient ServletConfig config;
public void init(ServletConfig config) throws ServletException {
		this.config = config;
		this.init();
	}

	public void init() throws ServletException {
	}
	public ServletConfig getServletConfig() {
		return this.config;
	}

      首先,为了方便能够在其他地方也能直接使用ServletConfig对象,而不仅仅局限在init(ServletConfig config)方法中,所以创建一个私有的成员变量config,在init(ServletConfig config)方法中就将其赋值给config,这样一来,GenericServlet和其子类都可以调用其getServletConfig()方法来获取ServletConfig对象了。

     之所以有空的init(),实际上就是为了后续的扩展和重写,有需要的情况下去覆盖init()而不是去覆盖init(ServletConfig config),因为后者一旦覆盖,就无法通过上述的方法在其他地方便捷地调用getServletConfig方法获取ServletConfig对象了。

2、其service()方法是个抽象方法,即它把处理请求的任务交给了子类。子类必须实现该方法。

  • HttpServlet :继承了GenericServlet,本身也是个抽象类,不能直接进行实例化,必须给出子类才能实例化(即不能直接使用,只能继承它)
  • HttpServlet是采用Http协议进行通信的,所以它也实现Http协议中的多种方法,每种方法可以处理相应类型的请求
  • HttpServlet的service()方法:继承自父类,它只接收HTTP请求,这里把相应的request和response转换为了基于HTTP协议的相应对象,最终将请求转到带protected关键字的service()方法中。
  • protected service()方法根据请求的类型将请求转发到相应的doDelete()、doGet()、doOptions()、doPost()、doPut()等方法中。所以开发自己的Servlet时,不需要覆盖HttpServlet的service()方法,因为该方法最终将请求转发相相应的doXXX方法中,只需要覆盖相应的doXXX方法进行请求处理即可。如果重写了该方法,那么就不会根据方法名调用其他具体的方法了。

注意:对于HttpServletd的service()中强转了参数根据请求的类型将请求转发到相应的方法中

     ServletRequest--->HttpServletRequest; 
     ServletResponse--->HttpServletResponse

三、理清楚逻辑后,看看Servlet的生命周期

Servlet之间的启动是有先后顺序的,这可以在web.xml中通过<load-on-startup>标签进行设定,参数为数字,表示了启动的顺序。启动顺序的默认值是0:

  • load-on-startup --> 0:Servlet被访问时才进行实例化
  • load-on-startup --> other:在容器启动时进行Servlet实例化

     即是说,默认不配置该参数的情况下,Servlet只有再被访问时才会实例化;配置了参数以后,根据参数按顺序在容器启动时就将Servlet实例化。例如:想要服务器一启动的时候就创建好servlet,

然后,Servlet的生命周期,其实说来也简单:

  • 容器在加载Servlet的时候,会执行其init()方法
  • 当接收请求的时候,会调用service(ServletReqeust request, ServletResponse response)方法,继而调用doGet或doPost方法
  • 在服务器关闭之前,会调用Servlet的destory()方法

最后简单总结下要点:

  • Servlet只初始化一次,它是单例的,只有一个实例,通过多线程访问。即Servlet是多线程单实例的;
  • 实例化过程中,先调用构造方法,再调用init方法,所以初始化操作可以覆盖写到init方法中;
  • 请求方式不同会调用doGet()或doPost()方法;
  • 根据实际情况在Servlet销毁前调用其destroy()方法;

继承HttpServlet实现一个简单的Servlet,只需要重写doPost()和doGet()方法

public class MyFirstServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        
    }

}

借鉴:https://www.cnblogs.com/deng-cc/p/7462866.html

https://blog.csdn.net/zhou_zhou_gogo1/article/details/84535731

https://blog.csdn.net/zhouym_/article/details/90741337

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值