1介绍:
servlet 是用Java编写的服务器端程序。其主要功能在于交互式地浏览和修改数据,生成动态Web内容。
Servlet运行于支持Java的应用服务器中。从原理上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。
2引入包:
最新的servlet已经升级到3.0版本了。在应用过程中,通过maven引入即可。
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
3 生命周期:
Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵循的过程:
- Servlet 通过调用 init () 方法进行初始化。
- Servlet 调用 service() 方法来处理客户端的请求。
- Servlet 通过调用 destroy() 方法终止(结束)。
- 最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。
在初始时调用init方法:public void init(ServletConfig config) throws ServletException; 此时通过ServletConfig读取相关配置参数。
初始化中也分为几种情况:
- Servlet容器启动时自动装载某些Servlet,实现它只需要在web.XML文件中的<Servlet></Servlet>之间添加如下代码:
<loadon-startup>
</loadon-startup>。
- 在Servlet容器启动后,客户首次向Servlet发送请求
- Servlet类文件被更新后,重新装载Servlet
Servlet被装载后,Servlet容器创建一个Servlet实例并且调用Servlet的init()方法进行初始化。在Servlet的整个生命周期内,init()方法只被调用一次。
每次服务器接收到一个 Servlet 请求时,服务器会产生一个新的线程并调用服务(servlet是单一的)。进入service方法执行: public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException; 如果是HttpServlet类,通过对请求的类型是GET还是POST等,再进入对应的方法:
@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");
}
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
service(request, response);
}
注意,传入参数ServletRequest req, ServletResponse res 在转换成HttpServletRequest,HttpServletResponse后,调用此类型的service方法。我们再看下这个方式的实现内容:
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 = 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);
}
}
可以看出,此方法中会根据请求的方法类型,再进入各个方法的实现。所以在实践过程中,我们一般创建自己的servlet方法,继承HttpServlet,重新定义doPost/doGet方法即可。
最后一个就是destroy方法了,destroy方法在容器移除servlet 时执行,同样只执行一次。这个方法会在所有的线程的service()方法执行完成或者超时后执行,调用这个方法后,容器不会再调用这个servlet的方法,也就是说容器不再把请求发送给这个servlet。这个方法给servlet释放占用的资源的机会,列如释放内存、文件句柄、线程等。
4 使用:
实际应用中,基本上有3类:直接实现Servlet接口、继承GenericServlet类、或继承HttpServlet类。其中一般servlet推荐使用Genericservlet,如果是在web中使用HttpServlet,它提供针对http的特殊实现的。
import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
@WebServlet(name="annotationServlet", urlPatterns={"*.an"}, initParams={
@WebInitParam(name="openFlag", value="true")
})
public class AnnotationServlet extends HttpServlet {
private boolean openFlag = false;
private int count = 0;
/**
* @Fields serialVersionUID : TODO
*/
private static final long serialVersionUID = 1L;
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
count ++;
System.out.println("AnnotationServlet --- service openFlag = " + openFlag + " count = " + count+"; AnnotationServlet hashcode:" + this.getServletInfo().hashCode());
super.service(req, resp);
}
@Override
public void destroy() {
System.out.println("AnnotationServlet --- destroy");
super.destroy();
}
@Override
public void init(ServletConfig config) throws ServletException {
// TODO Auto-generated method stub
super.init(config);
String openFlag = config.getInitParameter("openFlag");
this.openFlag = StringUtils.equals(openFlag, "true");
System.out.println("AnnotationServlet --- init" +"; AnnotationServlet hashcode:" + this.getServletInfo().hashCode());
}
}
---------------------------------------------------------------
import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoadOnStartUpServlet extends HttpServlet {
/**
* @Fields serialVersionUID : TODO
*/
private static final long serialVersionUID = 1L;
private int count = 0;
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
System.out.println("LoadOnStartUpServlet---service : count="+count+";LoadOnStartUpServlet hashcode:" + this.getServletInfo().hashCode());
super.service(req, resp);
}
@Override
public void destroy() {
System.out.println("LoadOnStartUpServlet---destroy");
super.destroy();
}
@Override
public void init(ServletConfig config) throws ServletException {
System.out.println("LoadOnStartUpServlet---init" +"; LoadOnStartUpServlet hashcode:" + this.getServletInfo().hashCode());
super.init(config);
}
}
--------------------------------------------------------------------------------------
import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class XmlServlet extends HttpServlet {
/**
* @Fields serialVersionUID : TODO
*/
private static final long serialVersionUID = 1L;
private int count = 0;
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
System.out.println("XmlServlet---service : count="+count+"; XmlServlet hashcode:" + this.getServletInfo().hashCode());
super.service(req, resp);
}
@Override
public void destroy() {
System.out.println("XmlServlet---destroy");
super.destroy();
}
@Override
public void init(ServletConfig config) throws ServletException {
System.out.println("XmlServlet---init"+"; XmlServlet hashcode:" + this.getServletInfo().hashCode());
super.init(config);
}
}
web.xml配置:
<servlet>
<servlet-name>loadOnStartUpServlet</servlet-name>
<servlet-class>com.zcl.servlet.LoadOnStartUpServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet>
<servlet-name>xmlServlet</servlet-name>
<servlet-class>com.zcl.servlet.XmlServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>xmlServlet</servlet-name>
<url-pattern>*.xs</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>loadOnStartUpServlet</servlet-name>
<url-pattern>*.lon</url-pattern>
</servlet-mapping>
以上定义了3个自定义的servlet,一个是web容器启动时就记载的loadOnStartUpServlet;一个是有请求过来时才创建的xmlServlet;一个也是有请求过来才创建的,但是使用注解方式的AnnotationServlet(在servlet3.*时提供的注解方式)。
运行时就可以看到他们的生命周期的过程。
5 异常处理:
当一个 Servlet 抛出一个异常时,Web 容器在使用了 exception-type 元素的 web.xml 中搜索与抛出异常类型相匹配的配置。
您必须在 web.xml 中使用 error-page 元素来指定对特定异常 或 HTTP状态码 作出相应的 Servlet 调用。
<error-page>
<error-code>405</error-code>
<location>/error.jsp</location>
</error-page>
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/error.jsp</location>
</error-page>