Welcome to “Algorithms and the Beauty of Programming” ↑ pay attention to us!
This article was first published on the wechat official account “Beauty of Algorithms and Programming”. Welcome to follow and learn more about this series of blogs in time.
Servlets are one of the most commonly used interfaces in JavaWeb development, especially the doGet() and doPost() methods in this interface. When we do Web development, we often define a Servlet such as HelloServlet, and make this class inherit HttpServelt, then override the doGet() method to quickly implement our own request service.
So what’s going on behind the doGet() method? The HttpServlet does a wrapper to determine the type of HTTP request and calls doGet() if it is a GET request or doPost() if it is a POST request.
What we’re looking for is not that simple answer, but what’s going on behind the scenes?
HelloServlet ->HttpServlet-> ApplicationFilterChain -> WsFilter -> StandardWrapperValve -> StandardContextValve -> StandardHostValve -> StandardEngineValve -> CoyoteAdapter -> Http11Processor -> NioEndpoint -> ThreadPoolExecutor -> Worker -> TaskThread -> Thread -> Catalina -> Bootstrap.main()
That’s what we want to get at the end of the day, starting with the doGet method, and gradually exploring where it starts, and where does that start end? The answer, of course, is the main function that starts the Tomcat program. Only after completing this process can we say that we fully understand the doGet() method and what is going on behind the scenes.
Through this series of blogs, you’ll get a thorough understanding of what’s going on behind the doGet() method, an in-depth understanding of Tomcat’s implementation mechanism from a source code perspective, how the core components of Tomcat work together, and learn WEB server design ideas.
1 goal
The goal of this blog source analysis series is to gain insight into the implementation mechanism of the doGet method in Tomcat. The goal of this source code analysis is to understand servlets.
2 Analysis Methods
First, write test code, and then use Intellij Idea stack window, thread window and single step debugging function to analyze its implementation Idea step by step.
The preparatory work is as follows:
1) Write the HelloServlet class.
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("hello"); }}Copy the code
2) Add servlet configuration to web.xml.
<servlet>
<servlet-name>helloServlet</servlet-name>
<servlet-class>HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
Copy the code
3) Test run
Your browser’s address bar: http://localhost:8080/hello
The final page displays the result: Hello
4) Enter the debugging and analysis stage.
Add a breakpoint before the doGet() method of the HelloServlet and click the debug button to enter the debug phase and start source analysis.
3 Analysis Process
Click the debug button to start analyzing the process.
First let’s look at the execution stack for the doGet() method.
- at HelloServlet.doGet(HelloServlet.java:17)
- at javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
- at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
- at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
- at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
- at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
- at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
- at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
- at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
- at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
- at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:475)
- at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
- at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80)
- at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:624)
- at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
- at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
- at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:498)
- at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
- at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:796)
- at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1368)
- at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
- at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
- at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
- at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
- at java.lang.Thread.run(Thread.java:748)
From the above we can see that there are 25 stack messages, which is very complicated to call, but these 25 stack messages are not where the program starts. We will show you where the program starts later.
To understand what’s going on behind the doGet() method, we need to understand the stack information, so we have 25 pieces of information so far, which we’ll walk you through step by step.
Due to the large content of the analysis, we will introduce it in several blogs. If you are interested in this series of blogs, please follow the wechat official account “Beauty of Algorithms and Programming” to learn more information in time.
To start with a brief introduction to the stack information,
HelloServlet.doGet(HelloServlet.java:17)
Represents the doGet() method of the HelloServlet class with 17 lines of code.
3.1 HelloServlet.doGet
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("hello"); / / 17
}
Copy the code
Line 17 of this is where we break, and where we users start writing programs. It simply writes a “hello” string to the HTTP response.
3.2 javax.mail. Servlet. HTTP. HttpServlet. Service
2. at javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
3. at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
We are going to analyze 2 and 3 together because they are both in the HttpServlet. Before we dive into the source code, let’s cover a few basics about servlets.
When we learned the basics of servlets, we all knew that servlets are server-side programs that handle requests from clients and then return a response. In most cases the request is an Http request, the response is an Http response, and the HTML code is included in the Http response.
A Servlet is an interface defined as follows:
public interface Servlet {
public void init(ServletConfig config) throws ServletException;
public ServletConfig getServletConfig(a);
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
public String getServletInfo(a);
public void destroy(a);
}
Copy the code
This interface definition is very simple, and the main methods are described as follows:
The init method represents the code executed when the Tomcat server first loaded the Servlet.
The Service method represents the code that the Servlet executes while processing the request.
The destroy method represents the code to execute when the servlet destruction is no longer used.
So we see that servlets have a life cycle, calling init when they are born, Service when they are requested, and destroy when they are destroyed.
In particular, the two parameter types of the service() method are ServeltRequest and ServletResponse.
Since we configured the web. XML to hand the request with access path ‘/hello’ to the HelloServlet to handle, in addition to the following inheritance by the HelloServlet:
– HelloServlet inherits HttpServlet
public class HelloServlet extends HttpServlet
Copy the code
– HttpServlet inherits GenericServlet
public abstract class HttpServlet extends GenericServlet
Copy the code
– GenericServlet implements the Servlet interface
public abstract class GenericServlet implements Servlet.ServletConfig.java.io.Serializable
Copy the code
We can conclude that HelloServlet is a JavaEE compliant Servlet and therefore capable of handling Http requests. According to the theory described above, when the Http request ‘/hello’ arrives at the server, It is processed by calling the Service method of the HelloServlet.
There is no service method in HelloServlet. This method is in its parent class, HttpServlet, and is defined as follows:
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);
}
Copy the code
As you can see from the above code, you force a ServletRequest to HttpServletRequest, force a ServletResponse to HttpServletResponse, and then hand it off to another service() method.
Why do you do this transformation? Why not just deal with ServletRequest and ServletResponse?
Welcome everyone to leave a message, say your view.
Once this type conversion is done, it is handed over to another service method.
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String method = req.getMethod();
if (method.equals(METHOD_GET)) {
// ...
doGet(req, resp);
} else if (method.equals(METHOD_POST)) {
doPost(req, resp);
} else if (method.equals(METHOD_PUT)) {
// ...
}
Copy the code
Get the Http request method type, and then call different methods according to the different type, such as method type get call doGet() method. Because the HelloServlet subclass implements the doGet() method, we end up executing the code we wrote above.
According to the analysis in §3.1 and §3.2, when a request reaches the Servlet, the request is first converted to HttpServletRequest, the response is converted to HttpServletResponse, and then the method type of the Http request is obtained. Finally, call different methods according to different method types to handle.
4 summarizes
This is the first article of “doGet method of Tomcat source code analysis”, which mainly introduces the goal and main tasks of source code analysis, and makes a very detailed introduction to the knowledge of Servlet, to help you better understand the Servlet. And why user-defined servlets need to inherit httpServlets.
ApplicationFilterChain 4, 5, 6, 7, 8
Please continue to follow the “Beauty of Algorithms and Programming” wechat official account to learn more.