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>
相关文章
相关标签/搜索