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方法,並根據響應的請求然后通過多態的方式調用相應的代碼!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM