Servlet的核心是Servelt那么我们就以此展开进回顾
Servlet接口定义如下:
package javax.servlet;
import java.io.IOException;
public interface Servlet {
public void init(ServletConfig config) throws ServletException;
public ServletConfig getServletConfig();
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;
public String getServletInfo();
public void destroy();
}
init、Service和destory是生命周期的方法:
(1) init()方法:当第一次请求Servlet时,创建完servlet对象的时候调用。只会调用1次。说明Servelt是单例,成员变量有线程安全的问题。
(2) service()方法:每次发出请求时调用。调用n次,也就是说每发出一次请求都会调用一次service()。
(3) destroy()方法: 销毁servlet对象的时候调用。停止服务器或者重新部署web应用时销毁servlet对象。只会调用1次。
其他两个非生命周期的方法:
getServletInfo():获取Servelt的描述信息
getServletConfig():获取封装Servelt配置的ServeltConfig
由于Servlet不是线程安全的,一个应用程序中所有的用户公用一个Servlet实例,因此不建议使用类级别的变量(只使用局部变量最好),除非是只读的或者java.utilconcurrent.atomic包中的成员。
其中涉及到的对象:
ServletRequest :
对于每一个HTTP请求,servlet容器会创建一个封装了HTTP请求的ServletRequest实例传递给servlet的service方法。
ServletResponse:
ServletResponse则表示一个Servlet响应,在调用service方法前,servelt容器首先创建一个ServeltResponse,并 将它作为第二个参数传给Service方法。其影藏了将响应发给浏览器的复杂性。
ServletConfig:
ServletConfig封装可以通过@WebServlet或者web.xml传给一个Servlet的配置信息,以这种方式传递的每一条信息都称做初始化信息,初始化信息就是一个个K-V键值对。为了从一个Servlet内部获取某个初始参数的值,init方法中调用ServletConfig的getinitParameter方法或getinitParameterNames方法获取,除此之外,还可以通过getServletContext获取ServletContext对象。
ServletContext:
ServletContext是代表了Servlet应用程序。每个Web应用程序只有一个context。在分布式环境中,一个应用程序同时部署到多个容器中,并且每台Java虚拟机都有一个ServletContext对象。有了ServletContext对象后,就可以共享能通过应用程序的所有资源访问的信息,促进Web对象的动态注册,共享的信息通过一个内部Map中的对象保存在ServiceContext中来实现。保存在ServletContext中的对象称作属性。
接着我们来看看Servlet的两个子类:
GenericServlet:
GenericServlet抽象类就是为了为我们省略一些模板代码,实现了Servlet和ServletConfig,完成了一下几个工作:
1、将init方法中的ServletConfig赋给一个类级变量,使的可以通过getServletConfig来获取。
2、为Servlet接口中的所有方法提供默认实现。
3、提供方法来包装ServletConfig中的方法。
HttpServelt
HttpServlet继承了GenericServlet,HttpServletRequest/Response继承了覆盖了ServletRequest/Response,成为了新的Servlet请求和响应的代表。在HttpServlet中覆盖了GenericServlet的service方法,并用新的Servlet请求和响应代表作为参数添加了一个service方法:
//覆盖GenereicServlet中的service
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException
{
HttpServletRequest request;
HttpServletResponse response;
if (!(req instanceof HttpServletRequest &&
res instanceof HttpServletResponse)) {
throw new ServletException("non-HTTP request or response");
}
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
service(request, response);
}
}
原始的service方法将请求和响应进行向下转换,分别为HttpServletRequest和HttpServletResponse,HttpServletRequest,HttpServletResponse由于带有了HTTP的特性,因此除了ServletRequest,ServletResponse中的方法之外还增加了几个可以获取HTTP特性信息的方法。
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);
}
}
Service方法会通过httpServeltRequest.getMethod()检查用来发送http请求的方法并调用doGet、doPut、doPost、doDelete、doHead、doTrace、doOptions这7种方法。这7种方法每一种都代表着一个http方法。
HTTP请求的方法:
HTTP/1.1协议中共定义了八种方法(有时也叫“动作”),来表明Request-URL指定的资源不同的操作方式
1、GET:请求指定的页面信息,并返回实体主体。
2、HEAD:类似于get请求,只不过返回的响应中没有响应体,用于获取消息头中的元信息
3、POST:向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。
4、PUT:向指定资源位置上传其最新内容。
5、DELETE:请求服务器删除Request-URL所标识的资源。
6、CONNECT:HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
7、OPTIONS:返回服务器针对特定资源所支持的HTTP请求方法,也可以利用向web服务器发送‘*’的请求来测试服务器的功能性
8、TRACE:回显服务器收到的请求,主要用于测试或诊断。