理解HttpServlet抽象类没有抽象方法
前两天复习了下Servlet,查看源码的时候发现了一个问题:HttpServlet已经实现了父类的所有抽象方法,为什么被定义成一个抽象类呢?想了好一阵。为了好理解我们就从Servlet–>GenericServlet–>HttpServlet一步步来看(顺便复习下Servlet)
1.Servlet
要新建一个servlet就要实现Servlet接口,我们来看Servlet接口里面的方法
①init(ServletConfig)当servlet类被加载时servlet容器会先调用servlet的空参构造器,然后调用init()方法并传入(ServletConfig(代表当前servlet的一些配置信息))
②getServletConfi()可以通过此方法获得ServletConfig
③ service(ServletRequest,ServletResponse)当有请求该servlet时,会调用该方法
④destroy 当卸载当前servlet容器时调用该方法销毁servlet
2.ServletConfi
可以看一下ServletConfig这个接口
①getServletName() 方法是可以返回当前servlet的名字(也就是web.xml文件中标签中中的值)
②getServletContext ()方法是返回ServletContext(当前web应用的上下文(每个web应用对应一个ServletContext,定义了servlet用来与servlet容器通信的多种方法))
③getInitParameter(string) 该方法可以根据名字来获取servlet的初始化参数
④getInitParameterNames ()该方法用来获取出初始化参数的参数名,注意返回类型为Enumeration 类型
每次要新建一个servlet都要实现Servlet接口(ServletConfig接口可不实现,因为ServletContext可以通过servletConfig.getServletContext()方法获得,前文提到ServletConfig接口是因为下面的GenericServlet要用到)重写这好几个方法是不是太麻烦好的,GenericServlet抽象类出现了
3.GenericServlet
该类实现了Servlet, ServletConfig接口并重写了方法,大家可自行查看源码,GenericServlet抽象类实现了上面讲到的两个接口的,所以很多方法不在赘述。我们来看其方法
①service(ServletRequest,ServletRespone) 该方法是servlet继承该抽象类后要实现的抽象方法,还是当请求该servlet时会调用该方法。、
比较有意思的是该类中有两个重载的init()方法:
②init(ServletConfig)该带参的init()方法是 GenericServlet 抽象类实现 servlet接口要实现的init方法,该方法会在servlet被加载时被servlet容器调用并传入ServletConfig
③ init()该空参的init() 方法是GenericServlet 抽象了自己新添加的init方法,目的是让继承该抽象类的servlet被加载并初始化时可以自己做些自定义的初始化。GenericServlet 中带参的init方法是这样写的:
@Override
public void init(ServletConfig config) throws ServletException { this.config = config; this.init(); }看到这里感觉继承 GenericServlet 抽象类再写servlet,必直接实现Servelt接口容易多了吧,别急后边还有更易用的就是HttpServlet
4.HttpServlet
该抽象类继承了GenericServlet 抽象类,并且重写了GenericServlet 中唯一的抽象方法service(ServletRequest,ServletRespone)方法我们来看看HttpServlet的方法
新的改变
该抽象类诸多方法读者可参看源码,我们就说一说其中的连个重载方法,service(ServletRequest , ServletResponse)该方法是HttpServlet继承GenericServlet实现的抽象方法,一个是HttpServlet自己定义的 service(HttpServletRequest, HttpServletResponse)方法
#####① service(ServletRequest , ServletResponse) 该方法作用是,由于我们的请求都是http请求,所以把ServletRequest请求下转型为HttpServletRequest(ServletRequest子接口),ServletRespone请求下转型为HttpServletRespone(ServletRespone子接口),以获取更多关于请求的信息(如请求方式等),并调用自定义的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(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; 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的时候只需要继承HttpServlet让后根据请求方式重写对应的doXXX()方法就行了吧!确实是。
前边讲了这么一堆,就讲了如何从Servlet迭代到HttpServlet这个过程,以及每个类或接口里边的方法。还没有说重点,为什么HttpServlet没有抽象方法,却定义成抽象类。
个人理解了好久觉得是这样的:如果HttpServlet不是抽象类的话,你就可以产生Httpser对象,但是单纯的HttpServlet对象时不能处理任何业务逻辑的,里边方法没有功能; 所以要定义成抽象类,防止你创建对象。 但是继承了HttpServlet类创建servlet就方便多了,你要根据自己需要然后重写需要的方法,让后自定义逻辑,这样就方便多了。总结:HttpServlet抽象类没有抽象方式是为了避免你自己创建一个没有业务功能的HttpServlet对象,但是给你一个提供了这样一个类方面你的servlet开发。(原创个人拙见,欢迎讨论)