适配器模式改造Servlet(GenericServlet)

Posted 一切随缘~~~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了适配器模式改造Servlet(GenericServlet)相关的知识,希望对你有一定的参考价值。

适配器模式改造Servlet(GenericServlet)

GenericServlet

  • 我们编写一个Servlet类直接实现Servlet接口有什么缺点?

    • 我们只需要service方法,其他方法大部分情况下是不需要使用的。代码很丑陋。
  • 适配器设计模式Adapter

    • 手机直接插到220V的电压上,手机直接就报废了。怎么办?可以找一个充电器。这个充电器就是一个适配器。手机连接适配器。适配器连接220V的电压。这样问题就解决了。
  • 之前的一篇博客写到抽象类的作用:降低接口实现类与接口之间的实现难度。

    (实现类不一定需要用到接口中定义的所有方法,可以先创建一个抽象类先实现一部分方法,留下实现类需要的方法,实现类再继承抽象类,实现需要的方法。)

  • 编写一个GenericServlet类,这个类是一个抽象类,其中有一个抽象方法service。

    • GenericServlet实现Servlet接口。
    • GenericServlet是一个适配器。
    • 以后编写的所有Servlet类继承GenericServlet,重写service方法即可
  • import javax.servlet.*;
    import java.io.IOException;
    
    public abstract class GenericServlet implements Servlet 
        @Override
        public void init(ServletConfig servletConfig) throws ServletException 
    
        
    
        @Override
        public ServletConfig getServletConfig() 
            return null;
        
    	// service设为抽象方法,留给子类去实现。
        @Override
        public abstract void service(ServletRequest servletRequest, ServletResponse servletResponse)
                throws ServletException, IOException;
    
        @Override
        public String getServletInfo() 
            return null;
        
    
        @Override
        public void destroy() 
    
        
    
    
    
  • 思考:GenericServlet类是否需要改造一下?怎么改造?更利于子类程序的编写?

    • 思考第一个问题:我提供了一个GenericServlet之后,init方法还会执行吗?

      • 还会执行。会执行GenericServlet类中的init方法。
    • 思考第二个问题:init方法是谁调用的?

      • Tomcat服务器调用的。
    • 思考第三个问题:init方法中的ServletConfig对象是谁创建的?是谁传过来的?

      • 都是Tomcat干的。
      • Tomcat服务器先创建了ServletConfig对象,然后调用init方法,将ServletConfig对象传给了init方法。
    • 思考一下Tomcat服务器伪代码:

      • public class Tomcat 
            public static void main(String[] args)
                // .....
                // Tomcat服务器伪代码
                // 创建LoginServlet对象(通过反射机制,调用无参数构造方法来实例化LoginServlet对象)
                Class class = Class.forName("com.baidu.javaweb.servlet.LoginServlet");
                Object obj = class.newInstance();
                
                // 向下转型
                Servlet servlet = (Servlet)obj;
                
                // 创建ServletConfig对象
                // Tomcat服务器负责将ServletConfig对象实例化出来。
                // 多态(Tomcat服务器完全实现了Servlet规范)
                ServletConfig servletConfig = new org.apache.catalina.core.StandardWrapperFacade();
                
                // 调用Servlet的init方法
                servlet.init(servletConfig);
                
                // 调用Servlet的service方法
                // ....
                
            
        
        
  • 再思考一下:

    • init方法中的ServletConfig对象是Tomcat小猫咪创建好的。

    • 这个ServletConfig对象目前在inti方法的参数上,属于局部变量

    • 那么ServletConfig对象以后肯定要在service方法中使用,怎么才能保证ServletConfig对象在service方法中能够使用呢?

      • 直接看代码:
      import javax.servlet.*;
      import java.io.IOException;
      
      public abstract class GenericServlet implements Servlet 
          // 成员变量
          private ServletConfig config;
          
          @Override
          public void init(ServletConfig servletConfig) throws ServletException 
      		// 将servletConfig 赋值给 config
              this.config = servletConfig;
          
      
          @Override
          public ServletConfig getServletConfig() 
              // 这里就可以返回config对象了。
              return config;
          
      
          @Override
          public abstract void service(ServletRequest servletRequest, ServletResponse servletResponse)
                  throws ServletException, IOException;
      
          @Override
          public String getServletInfo() 
              return null;
          
      
          @Override
          public void destroy() 
      
          
      
      
  • 再思考一下:

    • 如果继承GenericServlet的类,想要重写init方法呢?

      • 给init方法加上final,这样子类就无法重写init方法了。
    • 但是如果子类就是要重写init方法呢?

      • 解决办法:再GenericServlet类中添加一个无参的init方法,供子类进行重写。
  • 最终GenericServlet类的代码;

    • import javax.servlet.*;
      import java.io.IOException;
      
      public abstract class GenericServlet implements Servlet 
          // 成员变量
          private ServletConfig config;
      
          @Override
          public final void init(ServletConfig servletConfig) throws ServletException 
              // 将servletConfig 赋值给 config
              this.config = servletConfig;
              this.init();
          
          // 供子类重写
          public void init() 
              
          
          
          @Override
          public ServletConfig getServletConfig() 
              // 这里就可以返回config对象了。
              return config;
          
      
          @Override
          public abstract void service(ServletRequest servletRequest, ServletResponse servletResponse)
                  throws ServletException, IOException;
      
          @Override
          public String getServletInfo() 
              return null;
          
      
          @Override
          public void destroy() 
      
          
      
      
  • 值得庆幸的是:GenericServlet不需要我们程序员写,官方替我们写好了。

    • //
      // Source code recreated from a .class file by IntelliJ IDEA
      // (powered by FernFlower decompiler)
      //
      
      package javax.servlet;
      
      import java.io.IOException;
      import java.io.Serializable;
      import java.util.Enumeration;
      
      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 "";
          
      
          public void init(ServletConfig config) throws ServletException 
              this.config = config;
              this.init();
          
      
          public void init() throws ServletException 
          
      
          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();
          
      
      
      
    • 可以看到官方写的GenericServlet跟我们自己写的差不多,实现的思想是一样的。

以上是关于适配器模式改造Servlet(GenericServlet)的主要内容,如果未能解决你的问题,请参考以下文章

HttpServlet源码分析

get请求和post请求的区别

设计模式适配器模式

适配器模式 类适配器模式

11-GenericServlet

适配器模式--结构性模式