提及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