适配器模式改造 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跟我们自己写的差不多,实现的思想是一样的。

  • 25
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 48
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 48
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一切随缘~~~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值