什么是Servlet
Servlet技术就是Java在服务器端创建响应用户请求对象的技术,被创建的对象习惯上是称为一个Servlet对象。
Servlet就是部署在web服务器上的java程序。
servlet的生命周期
(1) 初始化Servlet对象。Servlet对象第一次被请求加载时,服务器初始化这个Servlet对象,即创建一个Servlet对象,对象调用init()方法完成必要的初始化工作。
(2)诞生的Servlet对象再调用service()方法响应客户的请求。
(3)当服务器关闭时,调用destroy()方法,消灭Servlet对象。
public void init(ServletConfig config) throws ServletException
第一次调用某个Servlet时,它的init方法将会被调用。在Servlet的一个生命周期中,仅会执行一次init方法。
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
HttpServletRequest request;
HttpServletResponse response;
try {
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
} catch (ClassCastException e) {
throw new ServletException(lStrings.getString("http.non_http"));
}
service(request, response);
}
该service方法将ServletRequest和ServletResponse转换为HttpServletRequest和HttpServletResponse,然后调用参数为Http的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;
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);
}
}
当请求发送到某个Servlet时,该Servlet的service方法都将被调用一次。service方法默认服务功能是调用与HTTP请求的方法相对应的doGet或doPost方法,doPost的方法实质上调用的还是doGet方法。
public void destroy()
当服务器停止服务,卸载Servlet时,该方法将被调用。
其中init()方法只执行了一次。
service()方法反复执行,只有是有请求就会执行该方法。
destroy()方法也只执行了一次。
Servlet线程安全
servlet不是线程安全的,从上面Servlet的生命周期可以看出,当第一次调用Servlet的时候,tomcat会根据web.xml配置文件实例化servlet,当后面又有请求访问该servlet的时候,不会再实例化该servlet。
servlet默认是单例模式,需要考虑线程安全的问题,在web容器中只创建一个实例,所以多个线程同时访问的时候是不安全的。
package com.dao.view;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/demoServlet")
public class demoServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private int count=10;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
if(count>0) {
count--;
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
在代码中如果是多线程在调用doGet()方法,在count临界的时候就可能会出现,由于多线程造成的错误。
解决方案
(1)让当前Servlet实现javax.servlet.SingleThreadModel 接口。
(2)在Servlet中不要使用成员变量,使用局部变量:
每个用户的每个请求都会调用service方法,而局部变量在service方法中,每一次都是新的空间。
(3)使用synchronized 关键字能保证一次只有一个线程