说起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方法,并根据响应的请求然后通过多态的方式调用相应的代码!

Java-Servlet请求方式doXXX、service 具体分析的更多相关文章

  1. 航信电子发票开发(servlet请求方式)

    在系统用户交费后,需要打印发票,可以选择普票或者机打票(票据信息在系统中自定义设置的),也可以打印电子发票,这里对接的是航信的电子发票,请求方式非web服务,而是使用servlet通过HTTP请求的方 ...

  2. Java Servlet(四):Servlet接口service工作(ServletRequest,ServletResponse对象)(jdk7+tomcat7+eclipse)

    本篇将会记录,Servlet接收客户端传递来的参数信息,并返回信息使用的对象,及这些对象的函数相关用法. 还是在java ee工程中进行操作,在WebContent目录下创建一个login.jsp文件 ...

  3. Java项目打包方式分析

    [TOC] 概述 在项目实践过程中,有个需求需要做一个引擎能执行指定jar包的指定main方法. 起初我们以一个简单的spring-boot项目进行测试,使用spring-boot-maven-plu ...

  4. Java Servlet (1) —— Filter过滤请求与响应

    Java Servlet (1) -- Filter过滤请求与响应 版本: Java EE 6 参考来源: Oracle:The Java EE 6 Tutorial: Filtering Reque ...

  5. [1.6W字] 浏览器跨域请求限制的详细原理分析&寻找一种最简单的方式实现XHR跨域(9种方法, 附大招可以纯前端实现跨域!)

    Title/ 浏览器跨域(CrossOrigin)请求的原理, 以及解决方案详细指南 #flight.Archives011 序: 最近看到又有一波新的创作活动了, 官方给出的话题中有一个" ...

  6. Java 集合 ArrayList和LinkedList的几种循环遍历方式及性能对比分析 [ 转载 ]

    Java 集合 ArrayList和LinkedList的几种循环遍历方式及性能对比分析 @author Trinea 原文链接:http://www.trinea.cn/android/arrayl ...

  7. Servlet请求参数的方式

    今天整理了以下几种常用的Servlet请求参数的方式,下面简单地介绍 1)getParameter(String key)返回一个字符串,获得name和key 一样的表单控件的数据,如果有重复的nam ...

  8. Java Servlet完全教程

    Servlet 是一些遵从Java Servlet API的Java类,这些Java类可以响应请求.尽管Servlet可以响应任意类型的请求,但是它们使用最广泛的是响应web方面的请求. Servle ...

  9. Java Servlet(六):HttpServlet实现原理(jdk7+tomcat7+eclipse)

    本篇记录了HttpServlet的实现过程,主要讲述了如何依赖Servlet,GenericServlet实现的原理. HttpServlet实现过程:1.是一个Servlet,继承自GenericS ...

随机推荐

  1. 你不得不知的几个互联网ID生成器方案

    服务化.分布式已成为当下系统开发的首选,高并发操作在数据存储时,需要一套id生成器服务,来保证分布式情况下全局唯一性,以确保系统的订单创建.交易支付等场景下数据的唯一性,否则将造成不可估量的损失. 基 ...

  2. zimg服务器图片数据迁移后,图片404异常的问题解决

    由于zimg特殊的图片存储结构及图片命名规则,其迁移数据应该当相当简单的,仅把对应的存储图片数据的文件夹复制即可.往往简单的东西总会有一些成本在里面,下面是我简单的迁移测试过程中遇到的一些问题,仅供参 ...

  3. dubbo webservice 区别

    DUBBO中可以设置采用webservice方式,进行数据交互. 随着交互系统的增多,这种方式对系统的侵入性越来越大,关系更为错综复杂,很容易出错. 较适用与外围系统通信,若是内部系统间则会出现以上较 ...

  4. Hadoop FAQ

    测试环境: Hadoop 2.6.0-cdh5.7.1 apache-kylin-2.0.0-bin kylin运行check-env.sh时,报如下警告: WARN util.NativeCodeL ...

  5. Excel催化剂开源第6波-Clickonce部署之自动升级瘦身之术

    Clickonce无痛自动更新是我最喜欢使用VSTO开发并Clickonce部署的特性之一,但这个自动更新,通常会更新整个程序文件,包含所有的引用dll和一些资源文件等. 一般来说,我们更新的都是主程 ...

  6. u盘制作启动盘步骤以及安装win10步骤

    1.下载制作工具:微PE工具箱V2.0 http://www.wepe.com.cn/download.html 2.默认制作启动盘 3.下载win10镜像 ed2k://|file|cn_windo ...

  7. [译]为任意网格计算tangent空间的基向量

    +BIT祝威+悄悄在此留下版了个权的信息说: [译]为任意网格计算tangent空间的基向量 Computing Tangent Space Basis Vectors for an Arbitrar ...

  8. 《VR入门系列教程》之4---运行平台

    运行平台     大多数的VR应用都可以在目前多数的PC和手机上运行,基本上一个不太旧的PC或者配置好点的笔记本电脑都可以正常运行Oculus Rift,如果手机的CPU和显卡不错的话也可以有很好的V ...

  9. Mybatis连接查询返回类型问题

    一对一映射 public class Card { private Integer id; private String num; private Student student; //重要 publ ...

  10. Java 获取操作系统相关的内容

    package com.hikvision.discsetup.util; import java.lang.reflect.Field; import java.net.InetAddress; i ...