一、什么是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