Java-Servlet請求方式doXXX、service 具體分析

提及Servlet的接收處理請求的方式,想必各位都並不陌生,如doGet、doPost、service...html

那麼他們的背後是如何執行?服務器怎麼選擇知道的?咱們就此來探討一下前端

 

本節案例的代碼奉上:java

web.xml部分web

<?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部分後續分析在具體展露。app

 

下面咱們來簡單的寫下具體用法,在作具體分析ide

 

doGet     相比不用說你們也都能見名知意,根據get的方式請求服務器post

前端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,請求方式改變了this

前端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  接收請求url

前端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方法,並根據響應的請求而後經過多態的方式調用相應的代碼!

 

原文出處:https://www.cnblogs.com/arebirth/p/javaservletreq.html

相關文章
相關標籤/搜索