Servlet学习笔记--GenericServlet类的由来

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,这样一来,通过configgetter方法就可以在任何地方使用到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方法。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值