Servlet面试题
- servlet的生命周期
- servlet的线程安全问题
- 如何解决?
- get 与 post 区别
servlet的生命周期
- servlet初始化—init()方法
①第一次创建Servlet时调用,只会执行一次初始化
②默认是第一次处理请求时创建Servlet,也可以设置为服务器第一次启动时就创建Servlet
public void init() throws ServletException {
// 初始化代码...
}
- servlet处理请求:service()方法
①处理来自浏览器的请求,将处理后的结果响应给浏览器
②servlet接收到请求后,调用service方法来进行处理,service中针对不同的请求进行匹配,选择调用doPost或doGet等方法
③在编写servlet时,需要实现doPost/doGet等方法
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getMethod();
long lastModified;
if (method.equals("GET")) {
//处理get请求
}
} else if (method.equals("HEAD")) {
} else if (method.equals("POST")) {
this.doPost(req, resp);
} else if (method.equals("PUT")) {
this.doPut(req, resp);
} else if (method.equals("DELETE")) {
this.doDelete(req, resp);
} else if (method.equals("OPTIONS")) {
this.doOptions(req, resp);
} else if (method.equals("TRACE")) {
this.doTrace(req, resp);
} else {
//其他
}
}
- servlet长时间没有被调用或服务器关闭,会调用destroy()方法销毁servlet,由JVM垃圾回收器来回收servlet
destroy方法只会执行一次
执行后,该servlet被标记为垃圾,等待回收
servlet的线程安全问题
servlet不是线程安全的
servlet是单例的,初始化后,只有长时间不再接受请求或容器关闭时,这个servlet才会销毁,多个请求线程都访问的是这一个servlet
一个servlet在处理第一次请求前进行实例化,初始化。或在容器启动时初始化(需要设置)
后续调用这个servlet的请求,都是独立的线程来调用service方法,存在线程安全问题
如何解决?
- 不在servlet中使用成员变量,线程之间没有资源竞争,线程安全
- 使用ThreadLocal为每个线程提供一份独立的变量
- 给处理请求的方法加锁;造成阻塞
protected synchronized void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
}
- 实现SingleThreadModel接口;会为每个用户创建一个servlet实例,性能差(已弃用)
public class DormServlet extends HttpServlet implements SingleThreadModel
get 与 post 区别
HTTP请求默认使用get
get | post |
参数在url中 | 参数在 resquest body 请求体中 |
有长度限制 | 没有长度限制 |
暴露在url中,不安全 | 隐藏在请求体中,安全 |
只能url编码 | 支持多种编码 |
产生一个TCP数据包 | 产生两个TCP数据包 |
获取服务器中的数据 | 修改服务器上的数据 |