专栏首页arebirth重生者的IT之路Java-Servlet请求方式doXXX、service 具体分析

Java-Servlet请求方式doXXX、service 具体分析

说起Servlet的接收处理请求的方式,想必各位都并不陌生,如doGet、doPost、service...

那么他们的背后是如何执行?服务器怎么选择知道的?我们就此来探讨一下

本节案例的代码奉上:

web.xml部分

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <servlet>
        <servlet-name>one</servlet-name>
        <servlet-class>cn.arebirth.servlet.MyServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>one</servlet-name>
        <url-pattern>/one</url-pattern>
    </servlet-mapping>
</web-app>

JSP部分

<%--
  Created by IntelliJ IDEA.
  User: Arebirth
  Date: 2019/8/17
  Time: 15:00
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>
      <form action="http://localhost:8080/ServletDemo_war_exploded/one" method="get">  <%--请求方式会改动--%>
        <label>Usercode:</label>
        <input type="text" name="name">
        <br/>
        <label>Password:</label>
        <input type="password" name="password">
        <br/>
        <input type="submit" value="Submit">
      </form>
  </body>
</html>

Servlet部分后续分析在具体展露。

下面我们来简单的写下具体用法,在做具体分析

doGet 相比不用说大家也都能见名知意,根据get的方式请求服务器

前端method:get请求

package cn.arebirth.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("MyServlet.doGet");
    }
}

结果
  MyServlet:doGet

doPost 方式同上doGet,请求方式改变了

前端method:post请求

package cn.arebirth.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MyServlet extends HttpServlet {

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

结果:
  MyServlet.doPost

service 接收请求

前端method:get or post方式皆可

package cn.arebirth.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MyServlet extends HttpServlet {

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

结果:
  MyServlet.service

正题来了前方高能!

分析1:当我们以GET请求方式进行请求的时候,servlet中只有doPost会怎么样?

package cn.arebirth.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MyServlet extends HttpServlet {

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

Result:

  会报 HTTP Status 405-Method Not Allowed 405错误状态码 服务器不允许以此请求方式访问

分析2:当我们以POST请求方式进行请求的时候,servlet中只有doGET会怎么样?

Result:

  同上,只是互换了一下还是会报405错误!

分析3:当我们以GET or POST请求方式进行请求的时候,servlet中只有doPost or doGet 和 service方法 那么它会执行谁?

//前端我们以get方式请求


package cn.arebirth.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MyServlet extends HttpServlet {

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

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

Result:

结果是输出
MyServlet.service

明明我们是以get方式进行请求的,而且servlet中含有doGet方法,为什么走的确实service??这是一个初学者的坑,让我们来探究下吧!

底层实现:我们的服务器在接受到请求的时候,servlet首先会查找是否service方法,因为servlet只认识service,原因看下图:

我们底层的servlet接口里面只有service接口!所以当我们的服务器接收到请求的时候首先会查找是否有service方法,如果没有的话则会去父类中调用,

分析4:我们就上面分析3中可以得知,如果没有servlet中没有重写service方法的话,那么它会调用父类的service方法,我们就此来分析

前端以get方式进行请求

package cn.arebirth.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MyServlet extends HttpServlet {

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

Result:  

结果输出的是:
  MyServlet.doGet

我们来分析下执行原理:

  首先请求达到这个servlet的时候,会查找本方法中是否有重写了的service方法,没有的话,将执行父类HttpServlet中的service方法首先会调用HttpServlet中一个重载的service方法,用于接收request和response,然后把request和response传递给另一个注的service重载的执行方法

public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        HttpServletRequest request;
        HttpServletResponse response;
        try {
            request = (HttpServletRequest)req;
            response = (HttpServletResponse)res;
        } catch (ClassCastException var6) {
            throw new ServletException("non-HTTP request or response");
        }

        this.service(request, response);   //这里吧request请求参数和response响应参数传递给另一个重载的方法并调用
    }


另一个重载的执行方法

protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String method = req.getMethod();//首先获取请求方式
    long lastModified;
  //接着判断请求方式,
    if (method.equals("GET")) {  
        lastModified = this.getLastModified(req);
        if (lastModified == -1L) {
            this.doGet(req, resp);   //如果是GET请求方式就会通过多态的方式调用者个doGet方式,
        } else {
            long ifModifiedSince;
            try {
                ifModifiedSince = req.getDateHeader("If-Modified-Since");
            } catch (IllegalArgumentException var9) {
                ifModifiedSince = -1L;
            }

            if (ifModifiedSince < lastModified / 1000L * 1000L) {
                this.maybeSetLastModified(resp, lastModified);
                this.doGet(req, resp);
            } else {
                resp.setStatus(304);
            }
        }
    } else if (method.equals("HEAD")) {
        lastModified = this.getLastModified(req);
        this.maybeSetLastModified(resp, lastModified);
        this.doHead(req, resp);
    } else if (method.equals("POST")) {//post方式的调用
        this.doPost(req, resp);
    } else if (method.equals("PUT")) {
        this.doPut(req, resp);
    } else if (method.equals("DELETE")) {
        this.doDelete(req, resp);
    } else if (method.equals("OPTIONS")) {
        this.doOptions(req, resp);
    } else if (method.equals("TRACE")) {
        this.doTrace(req, resp);
    } else {
        String errMsg = lStrings.getString("http.method_not_implemented");
        Object[] errArgs = new Object[]{method};
        errMsg = MessageFormat.format(errMsg, errArgs);
        resp.sendError(501, errMsg);
    }

}

通过上面的底层代码我们可以得知,它的底层实际上是不会直接调用我们servlet中写的doGet或doPost方法,而是间接的通过service方法判断请求方式,然后在通过多态的方式调用具体的请求,还是那句话因为它只认识service方法!!!!

分析4:当doGet or doPost和service方式同时存在,并且service方式中调用了父类的service方法,那么,它会得到什么结果??

前端以get方式进行请求


package cn.arebirth.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MyServlet extends HttpServlet {

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

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

Result:

结果输出的是:
    MyServlet.service
    MyServlet.doGet

这时有人就会说了,按照上面的例子来讲,如果有service方法存在的话,那么不就不会调用doGet or doPost了吗????

朋友,别忘了service方法里面还有 super.service(req,reps) 这句代码!!

通过上面的底层分析,我们可以得知,它首先会执行我们重写的service方法里面的代码,然后遇见了super.service(req,reps) ,这句代码是不是在调用父类HttpServlet的service方法??对吧。

所以他会根据响应的请求的方式,然后通过多态的方式调用了我们servlet中重写的doGet or doPost方法,所以这样就会一并执行啦!!

总结:

  servlet执行的时候值认识service方法,如过我们自己写的方法中没有service方法的话,那么它就会逐级往上面找直到找到service方法然后去执行,如:我们继承的HttpServlet抽象类,在它的里面找到了service方法之后,就会开始调用它的service方法,并根据响应的请求然后通过多态的方式调用相应的代码!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • dubbo配置负载均衡、集群环境

    再用dubbo作为项目架构的时候,给consumer消费者用nginx提供了负载均衡策略和集群的实现,

    Arebirth
  • MongoDB系列---用户及权限管理02

    2.1.2 查看admin中的用户 我们可以通过 db.system.users.find()函数来查看 admin 库中的所有用户信息...

    Arebirth
  • Spring整合Mybaits java.sql.SQLException: Access denied for user '***'@'localhost' (using password: YES

    最近在搞Spring和Mybatis的整合,当我们在Spring里面配置数据源,而数据源是从外部的properties文件读取过来的时候就会报错

    Arebirth
  • 我在Google用AI研究基因,入门从吴恩达的课程开始

    允中 编译 Google博客 量子位 出品 | 公众号 QbitAI ? Google AI入驻计划,是一项为期12个月的研究培训项目,希望帮助不同领域的科学...

    量子位
  • 专家展望未来5年深度学习发展趋势

    2015年已然过去,2016刚刚开始,回头将目光集中于去年的成就上,以及对将来科学趋势的预测。去年最令人瞩目的一个领域就是深度学习,它是机器学习中越来越流行的一...

    CSDN技术头条
  • 深度学习:远非人工智能的全部和未来

    现在每一个人都在学习,或者正打算学习深度学习(DL),它是目前人工智能诸多流派中唯一兴起的一个。各个年龄阶段的数十万人学习着免费和收费的深度学习课程。太多的创业...

    华章科技
  • 成为一名 AI 工程师永远都不晚

    用户1737318
  • 深度学习:远非人工智能的全部和未来

    选自Linkedin 作者:Fabio Ciucci 机器之心编译 参与:黄小天、路雪 人工智能的这一波热潮毫无疑问是由深度学习引发的,自吴恩达等人 2011 ...

    机器之心
  • Android学习笔记(八)深入分析Service启动、绑定过程

      Service是Android中一个重要的组件,它没有用户界面,可以运行在后太做一些耗时操作。Service可以被其他组件启动,甚至当用户切换到其他应用时,...

    codingblock
  • 机器如何学习?5分钟弄懂监督学习、无监督学习、半监督学习与强化学习

    导读:不知道你有没有这样的感受,想学点人工智能,却被一大堆名词吓坏? 想看点直白的说人话的简单介绍,却被各种绕来绕去的语言弄昏头? 没关系,本文就试图以最简单的...

    AI科技大本营

扫码关注云+社区

领取腾讯云代金券