Servlet继承体系详解

1.首先定义两个Servlet:AServlet和BServlet,如下图

image.png

image.png

2.问题一:如果我们需要在service方法中获取初始化参数,那么该怎么获取?
解决方案: 因为AServlet和BServlet中并没有ServletConfig对象,只有在init(ServletConfig servletConfig)方法中传入了这个对象,但是这个对象只能在init方法中使用,如果我们需要在service方法中访问到,只能在AServlet和BServlet中定义一个成员变量,并且在init方法中把ServletConfig对象赋值给这个成员变量,如下图

Servlet继承体系详解_第1张图片
2018-08-12_201043.png

2018-08-12_201044.png

3.问题二:虽然这样解决了问题一,但是我们程序员每次写Servlet的时候都要实现一些不常用的方法,比如getServletInfo(),getServletConfig(),destroy(),并且每次获取初始化参数都要重复一样的代码
解决方案:我们可以把这些重复的代码抽取出来,一般来说有两种方式,抽取到父类或者抽取为工具类,工具类人人都可以用,父类中的方法时只有子类可以用,在这里因为这是跟当前对象有关系,我们就抽取在父类中。所以我们写一个类MyGenericServlet,如下图,然后我们每次下一个Servlet类就可以继承自这个类,这样我们就可以不用实现Servlet中所有的抽象方法了,只需要根据自己的需求实现自己需要的方法,还有一点需要注意的是,把这些代码抽取到父类中以后,如果子类想要获取初始化参数的话,就只能在父类中提供一个方法向外获取ServletConfig对象,正好有那么一个方法叫做getServletConfig(),我们只需要将ServletConfig对象返回就好了

Servlet继承体系详解_第2张图片
2018-08-12_203615.png

Servlet继承体系详解_第3张图片
2018-08-12_4.png

3.问题三:本来获取初始化参数只需要使用本类中的ServletConfig对象直接调用方法就可以获取,现在我们却需要先获取这个ServletConfig对象之后再调用方法获取,感觉变的更复杂了,这怎么能忍
解决方案:我们可以在父类中定义一个方法来获取初始化参数,这样我们子类调用这个方法就可以直接获取到初始化参数了
如下图:

2018-08-12_5.png

Servlet继承体系详解_第4张图片
2018-08-12_6.png

4.问题四:我们发现getInitParameter(String str)这个方法在ServletConfig这个接口中本来就存在,并且如果是我们自己来定义这个方法,那么这个方法名就可以随意定义,造成别人可能都不知道这个方法的意义以及客户能会写错。
解决方法:让MyGenericServlet实现ServletConfig接口,并且实现里面的方法

2018-08-12_7.png

5.问题五:对于绝大多数请求来说都是Http协议的请求,那么该如何处理呢?
解决方案:把ServletRequest对象强转为HttpServletRequest对象,把ServletResponse对象强转为HTTPServletResponse对象
如下图:


Servlet继承体系详解_第5张图片
2018-08-12_8.png

6.问题六:每次写Servlet都要把这两个对象强转,麻烦
解决方案:我们来思考一下,如果把这两个强转放到父类MyGenericServlet的service(ServletRequest servletRequest, ServletResponse servletResponse)方法中是否可以?
因为我们子类中已经重写了service(ServletRequest servletRequest, ServletResponse servletResponse)方法,所以Tomcat服务器调用service(ServletRequest servletRequest, ServletResponse servletResponse)方法的时候是不会调用父类的service(ServletRequest servletRequest, ServletResponse servletResponse)方法的,所以不能把强转放到父类的service(ServletRequest servletRequest, ServletResponse servletResponse)方法中.
我们可以在父类中提供一个service(HttpServletRequest request,HttpServletResponse response)方法,并且不写任何实现,注意参数不同,然后在父类MyGenericServlet的service(ServletRequest servletRequest, ServletResponse servletResponse)方法中调用该方法,那么子类中只需要复写service(HttpServletRequest request,HttpServletResponse response)方法就可以,这样的话Tomcat服务器调用service(ServletRequest servletRequest, ServletResponse servletResponse)方法的时候就会调用到父类service(ServletRequest servletRequest, ServletResponse servletResponse),这样类型就强转成功,并且子类也拿到了HttpServletRequest对象和HttpServletResponse对象,如下图:

2018-08-12_9.png

Servlet继承体系详解_第6张图片
2018-08-12_10.png

7.问题七:因为我们刚才把强转放到了父类的service(ServletRequest servletRequest, ServletResponse servletResponse)方法中,这样的话不管什么类型的请求都会强转为Http类型,这样显然是不合适的
解决方法:为Http类型的请求单独封装一个类MyHttpServlet用来专门处理Http类型的请求,让这个类继承MyGenericServlet类,如下图,这样我们写处理Http类型的请求的时候只需要继承MyHttpServlet这个类

Servlet继承体系详解_第7张图片
2018-08-12_11.png

Servlet继承体系详解_第8张图片
2018-08-12_12.png

8.问题八:基于上述代码情况下,我们如果需要写初始化操作,需要在子类中重写init(ServletConfig servletConfig)方法,在这里我们可以思考一下,如果这里不调用super.init(servletConfig)父类初始化方法的话会怎么样?
这里肯定是需要调用父类的init方法的,因为父类的init方法是对ServletConfig对象进行初始化,如果不调用,则会报空指针异常
对于这一行代码,虽然不多,但是很可能会忘记,并且多写一行代码让人也很不爽的。。。。。。
解决方案:参考问题六,在父类中再提供一个init方法,主意这个init方法没有参数,然后在父类有参数的init方法中调用无参数的init方法,子类去如果有需要可以重写这个无参数init方法,如下图


2018-08-12_12.png

Servlet继承体系详解_第9张图片
2018-08-12_14.png

9.以后写Servlet来处理Http类型的请求的时候就可以继承MyHttpServlet类了。。查看源代码可以看到。Servlet和ServletConfig,GenericServlet,HttpServlet也是一样的实现方法和继承关系如下图


Servlet继承体系详解_第10张图片
2018-08-12_15.png

你可能感兴趣的:(Servlet继承体系详解)