一、Servlet概述
Servlet类是JavaWeb的三大组件之一,它属于动态资源。其作用是处理请求,服务器通常会把接收到的请求交由Servlet来处理,通常Servlet需要完成:
1.接收请求数据;
2.处理请求;
3.完成响应。
例如:当客户端发出登陆请求,或者输出注册请求时,这些请求都会交由Servlet来处理。
Servlet类中的方法需要由我们自己来实现,且每个Servlet必须实现javax.servlet.Servlet接口,之后由服务器来创建Servlet类对象并调用相应的方法。
二、Servlet的工作流程&原理
(一)工作原理
Servlet是运行在Servlet容器中的,由Servlet容器来负责Servlet实例的查找、创建以及整个生命周期的管理。Servlet整个生命周期可以分为四个阶段:
(1)类装载以及实例创建阶段:
默认情况下,Servlet实例是在接收到第一个请求时进行创建,并且在以后的请求中对这个实例进行复用。如果有Servlet实例需要进行一些复杂的操作(如打开文件,初始化网络连接等),可以配置在服务器启动时就创建实例。具体配置方法为:在web.xml的声明Servlet标签中添加<load-on-startup>1</load-on-start-up>标签。
(2)实例初始化阶段:
一旦Servlet实例被创建,将会调用Servlet中的init(ServletConfig arg)方法,传入ServletConfig,即Servlet的相关配置信息,init()方法在整个Servlet的生命周期中只会被调用一次。
(3)服务阶段:
实例初始化后,一旦由客户端请求,Servlet就会调用service(ServletRequest req, ServletRespose res)方法处理数据并响应数据。
(4)实例销毁阶段:
当Servlet容器决定销毁某个Servlet时,将会调用Servlet实例中的destory()方法,在destory()方法中进行资源释放。一旦Servlet实例的destory()方法被调用,Servlet容器将不会发任何请求给这个Servlet实例,若Servlet容器需要再次使用这个Servlet,需要重新实例化该Servlet实例。
需要注意的是:
在每一个应用中,每个Servlet只能拥有一个实例。
对于每一个Servlet实例,也有一个封装了对应配置的ServletConfig对象。
对于每一个应用程序,Servlet容器还会创建一个ServletContext对象,这个对象中封装了应用环境(上下文)的数据详情,每个应用程序也只有一个ServletContext。
(二)工作流程
1.web服务器接收http请求后将请求移交给Servlet容器;
2.Servlet容器对请求的URL进行解析并根据web.xml配置文件找到处理该应请求的Servlet,同时将request、response对象一并传递给该类;
3.Servlet根据根据request对象可以得到客户端发过来的数据并做出对应的处理,之后将需要返回的信息放入response对象中并返回到客户端;
4.Servlet一旦处理完请求,Servlet容器就会刷新response对象,并把控制权重新移交给web服务器。
三、实现Servlet的方式
(一)实现Servlet有三种方式:
1.实现javax.servlet.Servlet接口;
2.继承javax.servlet.GenericServlet类;
3.继承avax.servlet.http.HttpServlet类;(一般使用这种方式,方便!)
public interface Servlet{
public void init(ServletConfig config) throws ServletException;
public void service(ServletRequest req, ServletRespose res) throws ServletException,IOException;
public void destory();
public ServletConfig getServletConfig();
public String getServletInfo();
}
(二)、实现Servlet接口
上述Servlet接口五个方法中,init、service、destory是生命周期方法!
void init(ServletConfig servletConfig); // 在Servlet对象被创建后调用一次,用来初始化工作。
void service(ServletRequest req, ServletResponse res); // 每次处理请求时都会被调用。
void destory(); // 当应用程序被卸载或关闭Servlet容器时,该方法被调用,只能调用一次。
代码演示:
public class AServlet implements Servlet{
@override
public void init(ServletConfig config) throws ServletException{
System.out.println("init()...")
}
@override
public void service(ServletRequest req, ServletRespose res) throws ServletException,IOException{
System.out.println("service()...")
}
@override
public void destory(){
System.out.println("destory()...")
}
@override
public ServletConfig getServletConfig(){
return null;
}
@override
public String getServletInfo(){
return "";
}
}
编写完代码后需要在web.xml中正确配置映射关系。之后启动服务器,再多次访问Servlet,console中输出以下信息:

接下来关闭Servlet容器,控制台打印:

以上就是一个Servlet的完整生命周期。
注:Servlet中的方法实现后并不由我们自己来调用,而是由服务器来调用并做出反应。
四、Servlet接口相关类型
在Servlet接口中还存在三个我们不熟悉的类型:
ServletRequest:service()方法的参数,他表示请求对象,它封装了所有与请求相关的数据,它是由服务器创建的。
ServletResponse:service()方法的参数,它表示响应对象,在Servlet()方法中完成对客户端的响应需要这个对象。
ServletConfig:init()方法中的参数,它vlet配置对象,它对应Servlet的配置信息,对应web.xml文件中的<servlet>元素。
(一)ServletRequest和ServletResponse
ServletRequest和ServletResponse是service()方法中的两个参数,一个请求对象,一个响应对象,可以从ServletRequest对象中获取请求数据,可以使用ServletResponse对象完成响应。
ServletRequest和ServletResponse的实例由服务器创建,然后传递给
service()方法。如果在service()方法中希望使用HTTP相关功能,那么可以把ServletRequest和ServletResponse强转为HttpServletRequest和HttpServletResponse。这也说明我们经常需要在service()方法中对ServletRequest和ServletResponse进行强转,这是很麻烦的事,不过后面会有一个类来帮助我们解决这个问题。
(二)ServletConfig
ServleteConfig对象对应web.xml文件中的<servlet>元素。例如你想获取当前Servlet对象在web.xml文件中的配置名,那么可以使用ServletConfig.getServletName()方法获取!
ServletConfig对象是由服务器创建的,然后传递给Servlet的init()方法,可以在init()方法中使用它!
-String getServletName():获取Servlet在web.xml文件中的配置名称,即<servlet-name>指定的名称;
-ServletContext getServletContext():用来获取ServletContext对象。
-String getInitParameter(String name):用来获取在web.xml中配置的初始化参数,通过参数名来获取参数值;
Enumeration getInitParameter(String name):用来获取在web.xml中配置的所有初始化参数名称。
五、GenericServlet类
(1)GenericServlet是Servlet接口的实现类,我们可以通过继承GenericServlet来编写自己的Servlet。下面是Generic类的源代码:
GenericServlet.java
public abstract class GenericServlet implements Servlet,ServletConfig,java.io.Serializable{
private static final long = 1L;
privare transient ServletConfig config;
public GenericServlet() { }
@override
public void destory() {}
@override
public Enumeration<String> getInitParameterNames() {
return getServletConfig().getInitParameterNames();
}
@override
public ServletConfig getServletContext(){
return config;
}
@override
public ServletContext getServletContext(){
return getServletConfig().getServletContext();
}
@override
public String getServletInfo(){
return "";
}
@override
public void init(ServletConfig config) throws ServletException {
this.config = config;
init();
}
public void init() throws ServletException { }
public void log(String msg) {
getServletContext().log(getServletName() + ":" + message, t);
}
@override
public abstract void service(ServletRequest req, ServletResponse res) throws ServletExcrption, IOException;
@override
public String getServletName() {
return config.getServletName();
}
}
(2) GenericServlet的init()方法,即无参的init()方法。
在GenericServlet中,定义了一个ServletConfig config实例变量,并在init(ServletConfig)方法中把参数ServletConfig赋给了实例变量。然后在该类的很多方法中使用了实例变量config。
如果子类覆盖了GenericServlet的init(ServletConfig)方法,那么this.config = config这一条语句就会被覆盖,也就是说GenericServlet的实例变量config的值为null,那么所有依赖config的方法将都不能使用了。如果仍希望完成一些初始化操作,那么去覆盖GenericServlet提供的init()方法,它是没有参数的init()方法,且它会在init(ServletConfig config)中被调用。
(3)实现了ServletConfig接口
GenericServlet还实现了ServletConfig接口,所以可以直接调用getInitParameter()、getServletContext() 等ServletConfig的方法。
六、HttpServlet类
(1)HttpServlet概述
HttpServlet类是GenericServlet的子类,它提供了对HTTP请求的特殊支持,所以我们通常会通过继承HttpServlet来完成自定义的Servlet。
(2)HttpServlet中覆盖的service()方法
HttpServlet类中提供了service(HttpServletRequest, HttpServletResponse)方法,这个方法是HttpServlet自己的方法,不是从Servlet继承来的。在HttpServlet的service(ServletRequest, ServletResopnse)方法中会将ServletRequest和ServletResponse强转成HttpServletRequest和HttpServletResponse,然后再调用service(HttpServletRequest, HttpServletResponse)方法,这说明子类覆盖service(HttpServletRequest, HttpServletResponse)方法即可,这就不用要求自己去强转请求和响应对象了。
当然,在实际操作中,子类也不用去覆盖service(HttpServletRequest, HttpServletResponse)方法,因为HttpServlet还要做另一步简化操作,下面再介绍。
HttpService.java
public abstract class HttpServlet extends GenericServlet {
protected void service (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
......
}
@override
public void service (ServletRequest req, ServletResponse resp) throws ServletException, IOException {
ServletRequest request;
ServletResponse response;
try {
request = (HttpServletRequest)req;
response = (HttpServletResponse)resp;
} catch (ClassCastException e) {
throw new ServletException("non-Http request or response")
}
service(requst, response);
}
......
}
(3) doGet()和doPost()
在HttpServlet的service(HttpServletRequest, HttpServletResponse)方法会去判断当前请求是GET还是POST请求,如果是GET请求,那么会去调用本类的doGet()方法,如果是POST请求,则会去调用本类doPOST()方法,这说明我们在子类中只需要去覆盖doGet()和doPost()方法即可。
public class AServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("hello doGet()...")
}
}
public class BServlet extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("hello doPost()...")
}
}
七、ServletContext
(0)一个项目中只有一个ServletContext对象!!!
(1)ServletContext概述
服务器会为每个应用创建一个ServletContext对象:
ServletContext对象的创建是在服务器启动时完成的;
ServletContext对象的销毁是在服务器关闭时完成的。
ServletContext对象的作用是在整个Web应用的动态资源之间共享数据!
例如在AServlet中向ServletContext对象中保存了一个值,然后在BServlet中就可以获得这个值,这就是共享数据了。
(2)获取ServletContext
Servletconfig#getServletContext();
GenericServlet#getServletContext();
HttpSession#getServletContext();
ServletContextEvent#getServletContext().
在Servlet中获取ServletContext对象:
在void init(ServletConfig config)中:ServletContext context = config.getServletContext();,ServletConfig类的getServletContext()方法可以用来获取ServletContext对象;
在GenericServlet 或 HttpServlet中获取ServletContext对象:
GenericServlet类中有getServletContext()方法,所以可以直接使用this.getServletContext()来获取;
public class MyServlet implement Servlet {
public void init(ServletConfig config) {
ServletContext context = config.getServletContext();
}
......
}
public class MyServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse res) {
ServletContext context = this.getServletContext();
}
}
(3)域对象的功能
ServletContext是javaWeb四大域对象之一:
1.PageContext;
2.ServletRequest;
3.HttpSession;
4.ServletContext。
所有域对象都有存储数据的功能,因为域对象内部有一个Map,用来存储数据,下面是ServletConext用来操作数据的方法:
-void setAttribute(String name, Object value):用来存储一个对象,也可以称之为存储一个域属性,例如:servletContext.setAttribute("xxx", XXX),在ServletContext中保存了一个域属性,域属性名称为xxx,域属性的值为XXX。注:若多次调用该方法且使用相同的name,那么会覆盖上一次的值,这一特性与Map相同。
-Object getAttribute(String name):用来获取ServletContext中的数据,但被获取的数据需被存储过才行。
-void removeAttribute(String name):用来移除ServletContext中的域属性,如果参数name指定的域属性不存在,那么本方法什么都不做;
-Enumeration getAttributeNames():获取所有域属性的名称;
网友评论