概述
什么是Servlet
javax包下的一个interface,定义了Java处理web请求的标准,运行于Servlet容器(如 Tomcat,Jetty)中。Servlet有权访问所有的Java API,包括JDBC API。广义的Servlet指实现了Servlet接口的类。
Servlet干了什么
- 接收客户端请求
- 容器初始化并调用Servlet,Servlet生成响应内容
- 返回内容给客户端
Servlet的源码与组件
Servlet的方法和生命周期
public interface Servlet {
//初始化Servlet
public void init(ServletConfig config) throws ServletException;
//获取ServletConfig对象
public ServletConfig getServletConfig();
//用于处理一个请求
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;
//获取Servlet相关信息
public String getServletInfo();
//销毁
public void destroy();
}
以上代码及注释中,基本就可以看出生命周期了。需要注意的是destroy()
方法的调用时机,一般是指关闭容器。desttoy方法中会做一些销毁容器或清理一些资源的工作,和init()
方法一样在整个生命周期中只会被调用一次。
组件解析
Servlet的源码中,还出现了以下几个组件,对其作用进行简单概述。
ServletRequest
Servlet容器对于每一个请求,都会创建一个ServletRequest对象,将其作为参数传递给 Servlet的service方法。ServletRequest对象内封装了请求中参数名称和值,属性和输入流等信息。
ServletConfig
存储Servlet配置信息,包括服务端口,服务名称,远程地址,参数列表等。因为api太多就不贴了,感兴趣的可以去查元源代码或者api文档。
ServletResponse
从Servlet的源码来看,ServletResponse对象也是作为参数传递给service方法的,也就是说在调用service方法之前容器就创建了这个对象。ServletResponse对象中的getWriter()
方法返回了一个 java.io.PrintWriter
,如果没有指定字符集,默认使用ISO-8859-1编码,在传输中文的情况下会导致乱码。
ServletContext
ServletContext代表了应用本身,所以ServletContext是可以被当前所有的Servlet共享,所以ServletContext中存放的数据需要是线程安全的。
GenericServlet
GenericServlet是Servlet的默认实现,作用就是可以直接调用Servlet的方法,而不用自己去实现所有方法。因为GenericServlet还实现了ServletConfig,所以也可以直接调用ServletConfig的方法。此组件使用不多,用的比较多的还是熟悉的HttpServlet。
HttpServlet
使用http协议实现的实现类,继承自GenericServlet。HttpServlet重写了GenericServlet的service()
方法,源码如下。
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
//获取请求类型
String method = req.getMethod();
//根据请求类型进行路由,调用不同的请求类型处理方法,开发过程中只需要复写指定类型的方法即可
if (method.equals(METHOD_GET)) {
//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 = req.getDateHeader(HEADER_IFMODSINCE);
if (ifModifiedSince < lastModified) {
// 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);
}
}