适配器改造Servlet

举报
Java的学习之路 发表于 2022/03/24 11:05:53 2022/03/24
【摘要】 我们发现在编写一个Servlet类的时候,要实现它的所有方法,但是事实上,我们一般只是使用service方法,这样就会让代码看着很丑陋,那么我们要怎么解决呢?我们在说解决问题之前,先来看看这样的一个例子适配器设计模式Adapter手机直接插到220V的电压上,手机直接就报废了。怎么办?可以找一个充电器。这个充电器就是一个适配器。手机连接适配器。适配器连接220V的电压。这样问题就解决了。同样...

我们发现在编写一个Servlet类的时候,要实现它的所有方法,但是事实上,我们一般只是使用service方法,这样就会让代码看着很丑陋,那么我们要怎么解决呢?
我们在说解决问题之前,先来看看这样的一个例子

适配器设计模式Adapter

  • 手机直接插到220V的电压上,手机直接就报废了。怎么办?可以找一个充电器。这个充电器就是一个适配器。手机连接适配器。适配器连接220V的电压。这样问题就解决了。
    同样的道理,我们也可以使用这样的思想,来解决这个问题
  • 编写一个GenericServlet类,这个类是一个抽象类,其中有一个抽象方法service。

    GenericServlet实现Servlet接口。
    GenericServlet是一个适配器。
    以后编写的所有Servlet类继承GenericServlet,重写service方法即可。

package com.bjpowernode.servlet;

import jakarta.servlet.*;

import java.io.IOException;
import java.io.PrintWriter;

/**
 * @author zengyihong
 * @create 2022--03--06 20:08
 */
public class AServlet extends GenericServlet {
    @Override
    public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {


        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        //获取ServletContext对象
        ServletConfig config = this.getServletConfig();
        ServletContext context = config.getServletContext();
        out.print(context);
        


    }
}

思考:GenericServlet类是否需要改造一下?怎么改造?更利于子类程序的编写?

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

    • 还会执行。会执行GenericServlet类中的init方法。
    • 很明显,子类中如果这个方法,它就会去父类找相应的方法
  • 思考第二个问题:init方法是谁调用的?

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

    • 都是Tomcat干的。
    • Tomcat服务器先创建了ServletConfig对象,然后调用init方法,将ServletConfig对象传给了init方法。
    • 如果对上面几个问题不大理解的话,大家可以先去看看servlet的生命周期
  • 思考一下Tomcat服务器伪代码:

public class Tomcat {
    public static void main(String[] args){
        // .....
        // Tomcat服务器伪代码
        // 创建LoginServlet对象(通过反射机制,调用无参数构造方法来实例化LoginServlet对象)
        Class clazz = Class.forName("com.bjpowernode.javaweb.servlet.LoginServlet");
        Object obj = clazz.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方法
        // ....
        
    }
}

但是ServletConfig对象以后肯定是要在service方法中使用的,那么怎么才可以保证ServletConfig对象在service方法中能够使用呢? 我们很容易就想到了成员变量

init方法中的ServletConfig对是Tomcat服务器创建好的

  • 这个ServletConfig对象目前在init方法的参数上,属于局部变量
  • 那么怎么才能使用呢?------成员变量
  • ServletConfig对象将来肯定是要用在service方法的,怎么保证ServletConfig对象在service方法中调用呢-----调用getServletConfig()方法

思考一下,还有一种可能,需要子类重写父类的init方法,但是这样就会导致父类的init方法不执行,那么ServletConfig对象就是null了,那么将来就会有很大的麻烦,我们就不要让这个方法被子类重写,可以在方法加上final修饰,但是如果子类就是想要重写呢? 但是这个时候子类没有办法重写,那到底要怎么办呢
解决办法:再GenericServlet类中添加一个无参的init方法,供子类进行重写。
在这里插入图片描述
上面那个过程都是我们自己一步一步根据需求推出来的,是不是感觉好麻烦,一会这样,一会那样的,不过好消息是,GenericServlet这个类不需要我们写,官方已经提供好了,而且官方写的代码考虑的肯定比我们周全

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package jakarta.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();
    }
}

大家看到我们所写和官网提供的思路其实是大同小异的。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。