Servlet是JavaWeb应用中的最核心组件.而Servlet的生命周期又是通过Tomcat的Servlet容器调用的.首先看下JavaWeb的生命周期.
1.JavaWeb生命周期
- 启动阶段:加载Web应用的有关数据,创建全局的ServletContext对象,对Filter和一些Servlet进行初始化.
- 运行时阶段:为客户端提供服务.
- 终止阶段:释放Web应用所占用的各种资源.
1.1 启动阶段:
一,把web.xml文件中的数据加载到内存中.
二,为JavaWeb应用创建一个ServletContext对象.
三,对所有Filter进行初始化.
四,对那些需要在启动阶段就初始化的Servlet类进行初始化(在配置文件中有< load-on-startup>标签的)
1.2 运行时阶段
该阶段中,所有的Servlet都处于待命状态,随时可以响应客户端的特定请求,提供响应的服务.
1.3 终止阶段
销毁处于运行的Servlet,Filter,销毁所有和JavaWeb应用相关对象,如ServletContext对象,并且释放Web应用所占用的相关资源.
2.Servlet API
首先看下servlet结构图:
2.1 Servlet
其中的3个方法由Servlet容器调用,关于Servlet容器具体怎么调用这些方法,需要研究Tomcat的原理,这里本人也不是很清楚:(
init(ServletConfig config) 方法:容器在创建好Servlet对象后,就会调用该方法。
service(ServletRequest req,ServletResponse res) 方法:当容器接收到客户端访问特定的Servlet对象时,调用该Servlet的service方法.
destory() 方法:当Servlet对象结束生命周期时,容器会调用这个方法.
2.2 ServletConfig
getServletContext():该方法会返回一个ServletContext,该对象是Servlet容器加入的,由于是父接口,故在其下面的子类都可以通过这个方法得到全局的ServletContext.
其他方法都是获取web.xml中设置的值,如给一个Servlet添加初始化的值,需要在定义servlet节点下加入< init-param>标签.
2.3 GenericServlet
public abstract class GenericServlet implements Servlet, ServletConfig,
java.io.Serializable {
private static final long serialVersionUID = 1L;
private transient ServletConfig config;
public GenericServlet() {
// NOOP
}
@Override
public void destroy() {
// NOOP by default
}
@Override
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
public void init() throws ServletException {
// NOOP by default
}
@Override
public ServletConfig getServletConfig() {
return config;
}
@Override
public String getInitParameter(String name) {
return getServletConfig().getInitParameter(name);
}
@Override
public abstract void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;
...
...
...
很明显,该类是装饰类,其中有一个瞬时的ServletConfig对象,说明config对象在序列化时不会被保存到文件.
对于GenericServlet的子类,有两种初始化的方法,init()方法,如果想要与ServletConfig对象关联,在init()中加入super.init(config)就行了.
其中唯一的抽象方法是service(),指定子类为特定的客户实现的具体服务.
2.4 HttpServlet
其中定义了一些常量,如get方法,post方法,delete方法等.
2.4.1 doGet()
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_get_not_supported");
if (protocol.endsWith("1.1")) {
resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
} else {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
}
}
如果子类中没有重写doGet方法的话,会返回一个错误码和错误信息,其中的判断语句判断的是客户与服务器之间是否采用HTTP1.1协议通信.
2.4.2 service(ServletRequest req, ServletResponse res)
@Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
HttpServletRequest request;
HttpServletResponse response;
try {
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
} catch (ClassCastException e) {
throw new ServletException("non-HTTP request or response");
}
service(request, response);
}
该方法最终转到了service(HttpServletRequest req, HttpServletResponse resp)方法上.
2.4.3 service(HttpServletRequest req, HttpServletResponse resp)
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String method = req.getMethod();
if (method.equals(METHOD_GET)) {
long lastModified = getLastModified(req);
if (lastModified == -1) {
// servlet doesn't support if-modified-since, no reason
// to go through further expensive logic
doGet(req, resp);
} else {
long ifModifiedSince;
try {
ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
} catch (IllegalArgumentException iae) {
// Invalid date header - proceed as if none was set
ifModifiedSince = -1;
}
if (ifModifiedSince < (lastModified / 1000 * 1000)) {
// If the servlet mod time is later, call doGet()
// Round down to the nearest second for a proper compare
// A ifModifiedSince of -1 will always be less
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}
} else if (method.equals(METHOD_HEAD)) {
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);
} else if (method.equals(METHOD_POST)) {
doPost(req, resp);
} else if (method.equals(METHOD_PUT)) {
doPut(req, resp);
} else if (method.equals(METHOD_DELETE)) {
doDelete(req, resp);
} else if (method.equals(METHOD_OPTIONS)) {
doOptions(req,resp);
} else if (method.equals(METHOD_TRACE)) {
doTrace(req,resp);
} else {
//
// Note that this means NO servlet supports whatever
// method was requested, anywhere on this server.
//
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[1];
errArgs[0] = method;
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
}
}
该方法获取客户端的请求方式,然后根据请求方式来调用匹配的服务方法.如果为GET方式,就调用doGet()方法,以此类推.
3.ServletRequest ServletResponse
ServletRequest:
当Servlet容器接收到客户端要求访问特定Servlet的请求时,容器先解析客户端的原始请求数据,把它包装成一个ServletRequest对象,当容器调用Servlet对象的service()方法是,就可以把ServletRequest对象作为参数传给service()方法.
ServletResponse需要注意是:ServletResponse默认的正文MIME类型为text/plain,而HttpServletResponse的默认类型为text/html,即HTML文档类型.
4.ServletContext
4.1生命周期
当Servlet容器启动一个Web应用时,就会创建一个唯一的ServletContext对象,当Servlet容器终止一个Web应用时,就会销毁它的ServletContext对象,说明ServletContext生命周期和Web应用相同.
4.2 ServletContextListener
该监听器能监听ServletContext的生命周期,故可以使用它做一个网页被访问的次数.