源代码解析Servlet生命周期 转自segmentfault
2015-10-30 17:11
344 查看
之前在网上或者在一些面试题目上看到有关Servlet生命周期的题目,一下是我从某面试题目上截取的:
Servlet被服务器实例化后,容器运行其init方法,请求到达时运行其service方法,service方法自动派遣运行与请求对应的doXXX方法(doGet,doPost)等,当服务器决定将实例销毁的时候调用其destroy方法。
其实我想说的也和以上说的是一个流程,但是我认为如果联系源代码会不会更加清楚呢?题主是菜鸟一枚,所以还请大神们看到后可以给题主一些建议和意见。谢谢啦!!
我们一般编写Servlet的时候是让其继承HttpServlet然后重写doGet()和doPost()的。
我们可以通过看源代码得知HttpServlet是继承于一个通用的Servlet类叫做GenericServlet,而这个类又实现了Servlet接口。我就是从这三个关系来理解这个题目的
首先我们可以打开源代码看看Servlet接口的源代码,它定义了如下4种方法:
//是个初始化方法,这个方法是在Servlet被初始化的时候被调用,而且会有一个ServletConfig对象传递进来
//取到在web.xml配置的参数
//方法是用户处理客户机的请求的,这个方法的两个参数对应的是请求参数:req;和响应参数res。
//很少被使用
//是在servlet被销毁的时候调用。
GenericServlet
这是一个通用的Servlet类,题主认为这个抽象类就是可以扩展不同协议的Servlet,比如就是HttpServlet这个类
查看源代码后我们发现在这个类中,有关于Servlet的生命周期的方法
这个方法就是重写了Servlet接口中的方法,定位依旧是销毁Servlet
这也是重写了Servlet接口中的方法,但是我们在GenericServlet中发现了两个init()
一个是有参数,一个是无参数
无参数的init()是GenericServlet定义的,这个时候我们在看之前之前的结论Servlet被服务器实例化后,容器运行其init方法,这时会不会有疑问呢,那我们到底重写那个init()方法呢?
这确实是一个让人感到迷惑的问题,因为在Servlet接口当中定义了有参的init(),但是在GenericServlet中又出现了一个无参数的init()。我认为应该重写无参数的init(),因为我们可以由源代码得知有参数的init()调用了无参数的init()。如果我们重写了两个init()并将初始化代码又写到了无参数的init()中,但是又在有参数init()方法中没有写到super.init()那么程序将无法初始化。所以我认为还是重写无参数的init()
解决了init(),让我们再来看看源代码,这次我们来看了我们继承的类HttpServlet
这个类也是一个抽象类,我们在源代码中看到了很多提交方式包括doGet()和doPost()。但是我们也看到了两个service()。
通过源代码得知
这个service()是将request和response casting为HttpServletRequest和HttpServletResponse
然后再由这个service()选择使用doGet()还是doPost()或者是其他方式。
最后当服务器重新加载时就会调用destroy()
Servlet被服务器实例化后,容器运行其init方法,请求到达时运行其service方法,service方法自动派遣运行与请求对应的doXXX方法(doGet,doPost)等,当服务器决定将实例销毁的时候调用其destroy方法。
其实我想说的也和以上说的是一个流程,但是我认为如果联系源代码会不会更加清楚呢?题主是菜鸟一枚,所以还请大神们看到后可以给题主一些建议和意见。谢谢啦!!
我们一般编写Servlet的时候是让其继承HttpServlet然后重写doGet()和doPost()的。
我们可以通过看源代码得知HttpServlet是继承于一个通用的Servlet类叫做GenericServlet,而这个类又实现了Servlet接口。我就是从这三个关系来理解这个题目的
首先我们可以打开源代码看看Servlet接口的源代码,它定义了如下4种方法:
public void init(ServletConfig config) throws ServletException
//是个初始化方法,这个方法是在Servlet被初始化的时候被调用,而且会有一个ServletConfig对象传递进来
public ServletConfig getServletConfig()
//取到在web.xml配置的参数
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException
//方法是用户处理客户机的请求的,这个方法的两个参数对应的是请求参数:req;和响应参数res。
public String getServletInfo()
//很少被使用
public void destroy()
//是在servlet被销毁的时候调用。
GenericServlet
这是一个通用的Servlet类,题主认为这个抽象类就是可以扩展不同协议的Servlet,比如就是HttpServlet这个类
查看源代码后我们发现在这个类中,有关于Servlet的生命周期的方法
@Override public void destroy() { // NOOP by default }
这个方法就是重写了Servlet接口中的方法,定位依旧是销毁Servlet
@Override public void init(ServletConfig config) throws ServletException { this.config = config; this.init(); }
这也是重写了Servlet接口中的方法,但是我们在GenericServlet中发现了两个init()
一个是有参数,一个是无参数
public void init() throws ServletException { // NOOP by default }
无参数的init()是GenericServlet定义的,这个时候我们在看之前之前的结论Servlet被服务器实例化后,容器运行其init方法,这时会不会有疑问呢,那我们到底重写那个init()方法呢?
这确实是一个让人感到迷惑的问题,因为在Servlet接口当中定义了有参的init(),但是在GenericServlet中又出现了一个无参数的init()。我认为应该重写无参数的init(),因为我们可以由源代码得知有参数的init()调用了无参数的init()。如果我们重写了两个init()并将初始化代码又写到了无参数的init()中,但是又在有参数init()方法中没有写到super.init()那么程序将无法初始化。所以我认为还是重写无参数的init()
解决了init(),让我们再来看看源代码,这次我们来看了我们继承的类HttpServlet
这个类也是一个抽象类,我们在源代码中看到了很多提交方式包括doGet()和doPost()。但是我们也看到了两个service()。
通过源代码得知
@Override
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("non-HTTP request or response");
}
service(request, response);
}
这个service()是将request和response casting为HttpServletRequest和HttpServletResponse
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 / 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); } }
然后再由这个service()选择使用doGet()还是doPost()或者是其他方式。
最后当服务器重新加载时就会调用destroy()
相关文章推荐
- Servlet与JSP间的两种传值情况
- JSP、Servlet中get请求和post请求的区别总结
- jsp和servlet的区别探讨
- Struts2访问servlet分享
- java中Servlet处理乱码的方法
- Servlet 过滤器详细介绍
- JSP+Servlet+JavaBean实现登录网页实例详解
- servlet中session简介和使用例子
- 在Jsp Servlet中页面重新定向总汇
- JSP使用Servlet作为控制器实现MVC模式实例详解
- Servlet动态网页技术详解
- jsp和servlet操作mysql中文乱码问题的解决办法
- 基于jsp+servlet实现的简单博客系统实例(附源码)
- js调用后台servlet方法实例
- 利用JQuery和Servlet实现跨域提交请求示例分享
- JavaWeb编程 Servlet的基本配置
- java servlet 几种页面跳转的方法
- servlet 解决乱码问题
- JSP学习之Servlet用法分析