Servlet是server+Applet的缩写,表示一个服务器应用。Servlet就是一套规范,按照这套规范写的代码就可以直接在Java服务器上面运行。
Servlet是一套规范,那么在Java中规范则是接口。
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();
}
web.xml配置
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.lbx.servlet.HelloServlet</servlet-class>
<init-param>
<param-name>initParam</param-name>
<param-value>initValue</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
1 public void init(ServletConfig config) throws ServletException;
<load-on-startup>值</load-on-startup>
2 public ServletConfig getServletConfig();
getServletConfig()方法用来获取Servlet的配置,比如上面 <init-param>标签里面的参数。下面会详细介绍这个方法。
3 public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
service方法用于处于请求,web容器会解析HTTP协议,封装成对象传进去。
4 public String getServletInfo();
getServletInfo()获取servlet相关的信息,如作者、版权等,这个方法在需要自己实现,默认返回空字符串。
5 public void destroy();
destory()方法主要用于Servlet的销毁,当应用从tomcta移除或者关闭服务器时会被调用,用于释放资源,只会调用一次。
public interface ServletConfig {
public String getServletName();
public ServletContext getServletContext();
public String getInitParameter(String name);
public Enumeration<String> getInitParameterNames();
}
GenericServlet这个类实现了Servlet和ServletConfig接口(service()方法用abstract修饰了),可以直接调用Servlet和ServletConfig里的方法,比如获取ServletConfig中的方法时候可以直接调用,而无须调用getServletConfig().getServletContext()了,不过底层实现其实是在内部调用了,代码如下:
public ServletContext getServletContext() {
ServletConfig sc = getServletConfig();
if (sc == null) {
throw new IllegalStateException(
lStrings.getString("err.servlet_config_not_initialized"));
}
return sc.getServletContext();
}
GenericServlet实现了Servlet的init(ServletConfig config)方法,在里面将config复制给了内部变量config,然后调用无参的init()方法,这个方法是模板方法,在子类中可以通过覆盖它来完成自己的初始化工作。
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
public void init() throws ServletException {
}
这种做法有三个作用:
这个类是我们最常使用的类,继承了GenericServlet,写servlet直接继承就可以了,无需重新实现Servlet接口,这个类主要作用是如何处理请求。
看代码:
@Override
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");
}
//向下转型为HttpServletRequest
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
//调用http的处理方法
service(request, response);
}
问题一:为什么可以将ServletRequest 强转为HttpServletRequest呢?
因为在tomcat内部创建的这个request它就是httpServletRequest接口的子类。
问题二:为什么要将ServletRequest 强转为HttpServletRequest呢?
执行完上面方法,最后会调用service方法,调用的不是用一个service,因为传入参数类型不一样,重载方法
这个方法的作用是:获取Http请求类型,将不同请求类型路由到不同的处理方法。具体方法都是doXXX的结构,doGet,doPost,doPut,doDelete方法都是模板方法,而且如果子类没有实现将返回404错误页面。
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) {
doGet(req, resp);
} else {
long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
if (ifModifiedSince < lastModified) {
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);
}
}
流程图