前言
Servlet就是Server+Applet的缩写,表示一个服务器应用;
Servlet其实就是一套规范,我们按照这个规范写的程序就可以直接在Java服务器上运行;
Servlet接口
public interface Servlet {
//在容器启动的时候被调用,仅调用一次
//当load-on-startup设置为负数或不设置的时候,会在Servlet第一次调用时才会被调用,仅调用一次
void init(ServletConfig var1) throws ServletException;
//获取Servlet的配置(ServletConfig)
ServletConfig getServletConfig();
//具体处理一个请求
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
//获取与本Servlet相关的信息,如作者,版权等,这个方法需要自己实现,默认返回空字符串
String getServletInfo();
//用于在Servlet销毁(一般指关闭服务器)时释放资源,仅调用一次
void destroy();
}
Init方法在被调用时,会接收到一个ServletConfig类型的参数,它是容器传进去的;
ServletConfig就是Servlet的配置;我们在web.xml中定义Servlet时,通过init-param标签配置的参数就是通过ServletConfig保存的;
ServletConfig接口
public interface ServletConfig {
//用于获取Servlet名,web.xml中定义的servlet-name
String getServletName();
//非常重要:返回值ServletContext代表着这个应用本身
ServletContext getServletContext();
//获取init-param中的配置参数
String getInitParameter(String var1);
//获取配置的所有init-param名字集合
Enumeration<String> getInitParameterNames();
}
ServletContext就是Tomcat中Context的门面类ApplicationContextFacade,具体代码可以参考StandardContext的getServletContext;
既然ServletContext代表着应用本身,所以ServletContext里设置的参数就可以被当前应用的所有Servlet共享。在项目当中,我们知道参数可以保存在Session和Application中,而后者很多时候就是保存在ServletContext中的。
我们可以这么理解,ServletConfig是Servlet级别的,而ServletContext是Context(也就是Application)级别的。当然,ServletContext的功能非常强大,不是仅仅是保存参数;
说到这,那有没有比ServletContext级别更高的呢?也就是Tomcat中Host级别的,还是有的。ServletContext中有个public ServletContext getContext(String uirPath),它可以根据路径获取到同一站点下的别的应用的ServletContext。当然,为了安全,这个函数的返回值为null,可以手动更改。
ServletConfig和ServletContext最常见的用途是,传递初始化参数。GenericServlet实现类
GenericServlet是Servlet的默认实现类,是与协议无关的;
主要实现有三:
1.实现了ServletConfig接口,可以直接调用它的方法,而不再需要事先获得ServletConfig对象;
比如,获取ServletContext的时候,不再需要getServletConfig().getServletContxt(),直接调用getServletContxt()即可;
2.提供了无参的init方法;
3.提供了log方法:GenericServlet提供了2个log方法,一个记录日志,一个记录异常;具体实现是通过传给Servletontext的日志实现的;一般我们用自己的日志处理方式,所以这个用的不是很多;
HttpServlet实现类
HttpServlet是用HTTP协议实现的Servlet的基类,DispatcherServlet就是继承自HttpServlet;如果要自定义Servlet,直接继承HttpServlet即可;
HttpServlet是与协议相关的,所以更关心如何处理请求,即HttpServlet主要重写了service方法。在service方法中,首先将ServletRequest和ServletResponse转化为HttpServletRequest和HttpServletResponse,然后,根据Http请求类型的不同将请求路由到了不同的处理方法;
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
HttpServletRequest request;
HttpServletResponse response;
try {
// 转换request和response的类型
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
} catch (ClassCastException e) {
throw new ServletException("non-HTTP request or response");
}
// 调用http的处理方式
service(request, response);
}
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 {
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);
}
}
HttpServlet根据请求类型的不同将请求路由到不同的方法(doXXX,如doGet);子类需要对doXXX进行具体的实现,否则将抛出异常;
HttpServlet主要将不同的请求方式路由到了不同的处理方法;不过Spring MVC又将所有的请求合并到了统一的一个方法进行处理;