您当前的位置: 首页 >  servlet

white camel

暂无认证

  • 2浏览

    0关注

    442博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Servlet——分析和模拟实现Servlet继承关系

white camel 发布时间:2020-01-18 17:14:02 ,浏览量:2

目录
  • Servlet继承关系图
  • 分析GenericServlet的底层实现及模拟
  • 分析HttpServlet的底层实现及模拟
Servlet继承关系图

跳转到目录 在这里插入图片描述

分析GenericServlet的底层实现

跳转到目录

  • Aservlet.java
public class AServlet implements Servlet {

    private ServletConfig servletConfig;

    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        this.servletConfig = servletConfig;
    }

    @Override
    // 把ServletConfig对象暴露给子类访问
    public ServletConfig getServletConfig() {
        return this.servletConfig;
    }

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        String encoding = servletConfig.getInitParameter("encoding");
    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {
    }
}
  • BServlet.java
public class BServlet implements Servlet {

    private ServletConfig servletConfig;

    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        this.servletConfig = servletConfig;
    }

    @Override
    // 把ServletConfig对象暴露给子类访问
    public ServletConfig getServletConfig() {
        return this.servletConfig;
    }

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        String encoding = servletConfig.getInitParameter("encoding");
    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {

    }
}

问题: 上面的每自定义的Servlet类都得编写一些重复的代码,如此一来,我们需要重构代码,消除重复.

解决方案: 定义MyGenericServlet,用来定义一些自定义Servlet中的重复代码.

  • MyGenericServlet.java
abstract  public class MyGenericServlet implements Servlet {
    
    private ServletConfig servletConfig;
    
    @Override
    public void init(ServletConfig servletConfig) throws ServletException { 
    	// 把tomcat传递的ServletConfig赋值给本类的成员servletConfig,就是把它保存起来,方便其他方法使用!
        this.servletConfig = servletConfig;
    }

    @Override
    public ServletConfig getServletConfig() {
        return this.servletConfig;
    }

    @Override
    abstract public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException,IOException;
            
    @Override
    public String getServletInfo() {
        return null;
    }
    
    @Override
    public void destroy() {
    }
}

写完MyGenericServlet类后,让AServlet类和Bservlet类继承它.

  • AServlet.java
public class AServlet extends MyGenericServlet {
	public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException,IOException{
		String encoding = super.getServletConfig().getInitParameter("encoding");
	}
}

在这里插入图片描述

问题: 此时在AServlet中的service方法获取初始化参数: String encoding = super.getServletConfig().getInitParameter("encoding"); 如果想更进一步, 想在AServlet中的service方法中,这样写: String encoding = super.getInitParameter("encoding"); 解决方案: 让MyGenericServlet实现ServletConfig接口,并实现其方法,在实现方法中让父类来完成.

@Override
 public String getInitParameter(String s) {
     return servletConfig.getInitParameter(s);
 }

在这里插入图片描述

问题: 此时,如果AServlet需要做自身的初始化操作,怎么办? 应该在AServlet中覆盖init(config)方法,并在该方法中写初始化代码 在这里插入图片描述 如果忘记调用父类的init方法, 就会报空指针异常,针对于没写父类init方法,看下面的解决方案.

解决方案: 为了解决开发在做自身初始化操作的时候, 可能会忘记super.init(config), 需要在MyGenericServlet中,专门提供一个无参数的初始化方法: init, 专门暴露给子类用于子类做自身的初始化操作 在这里插入图片描述 上图的执行步骤:

  • 首先调用Servlet1的构造器, 创建Servlet的对象 obj.
  • 调用带有参数的Init方法完成初始化操作. obj.init(config), 此时Servlet1的父类(MyGenericServlet)总去找带有config参数的init方法,并调用.
  • 在MyGenericServlet中的带有参数的init方法: 先执行this.config=config,再调用this.init(); 表面上看在调用MyGenericServlet中无参数的init()方法.但是此时: Servlet1覆盖了init方法,从多态时方法调用上分析,此时 this.init(),实际上调用的是Servlet1的init方法

如此一来, 就确保了子类如何完成自身的初始化操作;

分析HttpServlet的底层实现

跳转到目录 问题: 但是上面的Servlet1只能处理一般的请求和响应,一般B/S开发,都是基于浏览器所以要遵循HTTP协议, 所以我们应该处理HTTP类型的请求和响应,需要重新设计, 处理Http的service方法,要统一处理GET/POST请求. 提供doGet方法和doPost方法 在这里插入图片描述 根据上图这样处理, 每一个Servlet都得编写这么多的代码.

解决方案: 提取出一个专门用于处理HTTP协议的Servlet出来, 创建MyHttpServlet类并继承MyGenericServlet

  • MyHttpServlet.java
public class MyHttpServlet extends MyGenericServlet {
    // 只能处理一般的请求
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
        // 调用处理Http请求的方法
        service(httpServletRequest, httpServletResponse);
    }

    public void service(HttpServletRequest reg, HttpServletResponse resp) throws ServletException, IOException {
        // 获取请求方式 GET/POST
        String method = reg.getMethod();
        if ("GET".equals(method)){
            doGet(reg, resp);
        } else if("POST".equals(method)){
            doPost(reg, resp);
        }
    }

    // 专门用于处理POST请求
    private void doPost(HttpServletRequest reg, HttpServletResponse resp) {
        System.out.println("AServlet.doPost()");
    }

    // 专门用于处理GET请求
    private void doGet(HttpServletRequest reg, HttpServletResponse resp) {
        System.out.println("AServlet.doGet()");
    }
}

抽取MyHttpServlet之后,以后开发,只需要继承于MyHttpServlet即可,再提供处理请求的service/doGet/doPost方法. 这里也体现了模板方法设计模式

以后写的XxxServlet都要继承HttpServlet

在这里插入图片描述

public class TestServlet extends HttpServlet {
    @Override
    public void init() throws ServletException {
        // 初始化代码
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("service()----");

        // 不要调用父类的service
//        super.service(req, resp);
    }
}

注意: 在service方法中不要调用父类的service方法 否则会报 在这里插入图片描述

关注
打赏
1661428283
查看更多评论
立即登录/注册

微信扫码登录

0.0909s