Tomcat8源碼分析-請求處理過程(含源碼中新建web應用一塊兒調試)

上一篇:Tomcat8源碼分析-啓動流程-start方法html

 此篇主要將Tomcat8從接收請求處處理請求的時序圖畫出來,並用文字描述一下主要流程java

時序圖

圖片有點大,須要點開了放大看web

說明

文字描述流程以前先提示以下兩點:
1.Acceptor、Poller、SocketProcessor都是NioEndpoint的內部類apache

2.Tomcat不必定只有NioEndpoint還有Nio2Endpoint AprEndpoint,只是常規的請求和默認都使用的是http和nio,因此在時序圖中就用NioEndpoint了tomcat

 

Acceptor負責接收發起的請求,通過NioEndpoint和Poller將socket最終包裝爲一個PollerEvent放入到SynchronizedQueue同步隊列當中,接着繼續等待新的請求到底重複前面的步驟app

Poller循環判斷同步隊列中是否有問題處理的Event,若是有則使用WindowsSelectorImpl讀取socket,將socket中的attachment添加到SocketProcessor( implements runnable),使用線程池啓動SocketProcessorwebapp

SocketProcessor通過一層層調用直到按照StandardEngine-StandardHost-StandardContext-StandardWrapper順序執行它們的Pipeline.First Valve,最後由StandardWrapperValve執行Servlet的加載,加載完後會調用Servlet的init方法,而後由ApplicationFilterChain調用HttpServlet的service,進而調用到本身的Servlet中的doXxx方法socket

如圖:jsp

 

CoyoteAdapter裏面的postParseRequest方法包含了很是重要的根據path找到對應Servlet的邏輯,具體規則以下:maven

先精確匹配-通配符匹配-後綴名匹配(默認有jsp和jspx,這也是爲何能夠處理jsp的緣由)-Welcome資源匹配-前面都沒匹配到就是DefaultServlet

匹配成功以後,StandardWrapperValve對應的StandardWrapper.servlet纔會是咱們想要的,才能實現真正的業務調用。

總結:

1.接收請求參數的流程仍是比較簡單清晰,裏面使用了模板方法模式、責任鏈模式(如Pipeline的執行)、門面模式等。

2.裏面發現了兩種擴展點

  • 自定義Valve,將Valve配置到不一樣容器下面,能夠在不一樣時間點和範圍(調用順序決定)做用與請求過程
  • 自定義Filter,Filter是配置在應用的web.xml中的,只能做用與當前這個應用,而且能夠配置Filter攔截的請求格式

3.要想快速搞清楚調用過程,建議直接在自定義的Servlet方法中加斷點,要達到這個效果須要新建的web應用和tomcat是在同一個項目中,方式以下:

先看看idea中的目錄結構

圖中還有一處沒有標記出來:就是在idea中選擇新建了一個maven的web-module以後是沒有源碼目錄的,我是在main下新建的一個java目錄,而後右鍵標記爲source root,再在目錄下編寫Servlet的

Servlet代碼

package com.jv.tomcat;

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 TestServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setHeader("content-type", "text/html;charset=UTF-8");
        resp.setCharacterEncoding("UTF-8");
        System.out.println("My TestServlet  doGet");
        resp.getWriter().print("<html><body><h1>My TestServlet  doGet</h1></body></html>");
    }
}

看看pom.xml

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>apache-tomcat-8</artifactId>
        <groupId>gxf</groupId>
        <version>1.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>testweb</artifactId>
    <packaging>war</packaging>

    <name>testweb</name>
    <url>http://www.example.com</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
        <!-- 配置了這個依賴,須要將tomcat源碼install到本地maven倉庫,不然會提示依賴不存在 -->
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-8</artifactId>
            <version>8.5</version>
        </dependency>
    </dependencies>

    <build>
        <finalName>testweb</finalName>
        <pluginManagement>
            <plugins>
                <plugin>
                    <artifactId>maven-clean-plugin</artifactId>
                    <version>3.1.0</version>
                </plugin>
                <plugin>
                    <artifactId>maven-resources-plugin</artifactId>
                    <version>3.0.2</version>
                </plugin>
                <!-- 編譯的時候將class文件輸出到配置目錄下,由於打war包的時候會從整個目錄複製class文件 -->
                <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.0</version>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                        <encoding>UTF-8</encoding>
                        <outputDirectory>F:\projects\own\tomcat-8.5.49\testweb\src\main\webapp\WEB-INF\classes</outputDirectory>
                    </configuration>
                </plugin>
                <plugin>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.22.1</version>
                </plugin>
                <!-- 打war包,並將war包複製到tomcat的工做目錄下 -->
                <plugin>
                    <artifactId>maven-war-plugin</artifactId>
                    <configuration>
                        <archiveClasses>true</archiveClasses>
                        <outputDirectory>F:\projects\own\tomcat-8.5.49\deploy-test\webapps</outputDirectory>
                    </configuration>
                    <version>3.2.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-install-plugin</artifactId>
                    <version>2.5.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-deploy-plugin</artifactId>
                    <version>2.8.2</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>
相關文章
相關標籤/搜索