欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-05-29 10:10:13
说起Servlet的接收处理请求的方式,想必各位都并不陌生,如doGet、doPost、service... 那么他们的背后是如何执行?服务器怎么选择知道的?我们就此来探讨一下 本节案例的代码奉上: web.xml部分 JSP部分 Servlet部分后续分析在具体展露。 下面我们来简单的写下具体用法 ......

说起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错误状态码  服务器不允许以此请求方式访问

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

分析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,原因看下图:

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