Servlet学习笔记–GenericServlet类的由来
Servlet对象的有关知识
适配器
-
我们每次在创建一个Servlet对象时,我们用的最多的就是
service
方法,其他的方法我们几乎都不怎么用,但是每次创建类的时候都要重写,就很丑陋,这个时候,我们可以引入适配器这一个东西,也就是接口的通用实现类。举个例子:-
现在有一个接口A,他有五个抽象方法----
m1(),m2(),m3(),m4(),m5()
,现在有一些接口B1,B2,B3,B4,B5……要实现A接口并且只需要实现他的m1方法,其他方法不需要,如果像平常一样,直接实现接口A,那么需要重写5个方法,但是这5个方法我们就只需要用到一个方法,全部都重写显得很臃肿,有没有一种方法可以既实现接口但是可以只重写一个方法呢?有的,直接创建一个接口的实现类GennericA实现接口A,同时将m1方法改为抽象方法,这样如果以后有与业务需求B相同的实现类时。
//普通方法 Class B1 implements A{ public void m1(){} public void m2(){ System.out.println("This is B1's m2 method"); } public void m3(){} public void m4(){} public void m5(){} } Class B2 implements A{ public void m1(){} public void m2(){ System.out.println("This is B2's m2 method"); } public void m3(){} public void m4(){} public void m5(){} } Class B3 implements A{ public void m1(){} public void m2(){ System.out.println("This is B3's m2 method"); } public void m3(){} public void m4(){} public void m5(){} }
//使用适配器 abstract Class AllBClass implements A{ public void m1(){} public abstract void m2(){} public void m3(){} public void m4(){} public void m5(){} } Class B1 extends AllBClass{ public void m2(){ System.out.println("This is B1's m2 method"); } } Class B2 extends AllBClass{ public void m2(){ System.out.println("This is B2's m2 method"); } } Class B3 extends AllBClass{ public void m2(){ System.out.println("This is B3's m2 method"); } }
显而易见,下面这种使用适配器的方式比上面的普通方式代码开发起来更加便捷。
-
适配器应用
-
了解完适配器,接下来将适配器的知识应用到Servlet对象的创建中:
abstract Class AllServletClass implements Servlet{ @Override public void init(ServletConfig servletConfig) throws ServletException { } @Override public ServletConfig getServletConfig() { return null; } @Override public abstract void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { } @Override public String getServletInfo() { return null; } @Override public void destroy() { } } Class AServlet extends AllServletClass{ @Override public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { System.out.println("This is AServlet's service method"); } } Class BServlet extends AllServletClass{ @Override public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { System.out.println("This is BServlet's service method"); } }
init方法
-
下面来剖析一下这个通用类中的
init
方法:-
init
方法与无参构造一样,都是在对服务器发送请求时调用仅一次,所以为什么有无参构造还要有一个init
方法呢? -
在Servlet编写规范中,不建议自己写构造方法,因为如果自己创建了有参的构造方法,那么会自动覆盖掉无参数的构造方法,而Tomcat服务器在创建中只会调用无参构造(可以自己在无参构造里加一条输出语句测试),为了防止这种低级的错误,所以添加了一个
init
方法,用来供JavaWeb程序员进行一些成员变量的初始化。 -
那么,既然如此,我们需要做一些什么变量的赋值呢 ?
-
首先,直接看方法,可以看到在调用
init
方法时传递了一个参数,是一个ServletConfig
类型的变量,因为init
方法时Tomcat服务器调用的,所以这个变量是Tomcat服务器创建的,但是,假如某一天,我们有业务需求在service
方法中使用到这个变量的话怎么办呢 ?我们在调用service
方法的时候并没有传递这样一个参数,就算我们自己再写一个传递该变量的service
方法,Tomcat调用的还会是没有传递的那个方法,因为调用的函数都是写死的,但是我们还有一个办法,就是在这个接口实现类当中定义一个私有变量config
,并且定义它是一个ServletConfig
类型的变量,这样我们在init
方法中将传进来的参数赋值给成员变量config
,这样一来,通过config
的getter
方法就可以在任何地方使用到Tomcat服务器创建的变量了。最最重要的是,这个getter
方法正好是Servlet接口需要实现的五个方法之一:所以我们只需要对这个实现类稍作修改,如下:abstract Class AllServletClass implements Servlet{ //改动部分1 private ServletConfig config; @Override public void init(ServletConfig servletConfig) throws ServletException { //改动部分2 this.config = servletConfig; } @Override public ServletConfig getServletConfig() { //改动部分3 //return null; return config; } @Override public abstract void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { } @Override public String getServletInfo() { return null; } @Override public void destroy() { } }
这样修改后,我们就可以通过
getServletConfig
方法随时获取和使用config
变量了。
-
But,这个东西只是接口实现类,如果这样写那以后继承他的类岂不是不能重写
init
方法了?就算重写难道就必须加上一个私有变量? -
这显然是不可取的,所以有没有办法既能保留以上更改,又能为子类提供一个供子类初始化的解决办法呢?
-
当然可以,我们再创建一个
init
方法,但是不给这个方法传参数,在有参数的init
方法中调用这个无参数的方法,这样以后的子类只需要重写覆盖掉无参数的init
方法,实现完整的初始化。这就是GenericServlet
类的由来,如下是源代码: -
public abstract class GenericServlet implements Servlet, ServletConfig, Serializable { private static final long serialVersionUID = 1L; private transient ServletConfig config; public GenericServlet() { } public void destroy() { } public String getInitParameter(String name) { return this.getServletConfig().getInitParameter(name); } public Enumeration<String> getInitParameterNames() { return this.getServletConfig().getInitParameterNames(); } public ServletConfig getServletConfig() { return this.config; } public ServletContext getServletContext() { return this.getServletConfig().getServletContext(); } public String getServletInfo() { return ""; } //注意这里!!! //begin public void init(ServletConfig config) throws ServletException { this.config = config; this.init(); } public void init() throws ServletException { } //end public void log(String message) { this.getServletContext().log(this.getServletName() + ": " + message); } public void log(String message, Throwable t) { this.getServletContext().log(this.getServletName() + ": " + message, t); } public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException; public String getServletName() { return this.config.getServletName(); } }
-
上面所展示的这个类是jdk自带的可继承类GenericServlet,继承这个类就只需要重写
service
方法,还能选择性的重写无参数的init
方法。
-