Tomcat完整笔记

1. Tomcat的安装和配置环境变量

安装

到官网下载需要的Tomcat版本的压缩包即可

注意:Tomcat 9 对应的JRE必须>=JRE 8;Tomcat 8 7同理

然后解压到指定的文件夹;目录名为:“apache-tomcat-[version]”

(WINDOWS和Linux)一样的效果

配置环境变量

配置JRE环境变量,变量名为:CATALINA_HOME(required)和CATALINA_BASE(optional)

前者必须,后者可选

CATALINA_HOME:tomcat根目录的路径

CATALINA_BASE:用于Advanced Configuration - Multiple Tomcat Instances 多个Tomcat实例

==================================================
Advanced Configuration - Multiple Tomcat Instances
==================================================

In many circumstances, it is desirable to have a single copy of a Tomcat
binary distribution shared among multiple users on the same server.  To make
this possible, you can set the CATALINA_BASE environment variable to the
directory that contains the files for your 'personal' Tomcat instance.

When running with a separate CATALINA_HOME and CATALINA_BASE, the files
and directories are split as following:

In CATALINA_BASE:

 * bin  - Only the following files:

           * setenv.sh (*nix) or setenv.bat (Windows),
           * tomcat-juli.jar

          The setenv scripts were described above. The tomcat-juli library
          is documented in the Logging chapter in the User Guide.

 * conf - Server configuration files (including server.xml)

 * lib  - Libraries and classes, as explained below

 * logs - Log and output files

 * webapps - Automatically loaded web applications

 * work - Temporary working directories for web applications

 * temp - Directory used by the JVM for temporary files (java.io.tmpdir)


In CATALINA_HOME:

 * bin  - Startup and shutdown scripts

          The following files will be used only if they are absent in
          CATALINA_BASE/bin:

          setenv.sh (*nix), setenv.bat (Windows), tomcat-juli.jar

 * lib  - Libraries and classes, as explained below

 * endorsed - Libraries that override standard "Endorsed Standards"
              libraries provided by JRE. See Classloading documentation
              in the User Guide for details.
              This is only supported for Java <= 8.
              By default this "endorsed" directory is absent.

Tomcat官方说:CATALINA_HOME相当于Tomcat的安装目录,而CATALINA_BASE则是Tomcat的工作目录

所以CATALINA_BASE的存在就是为了实现多个Tomcat实例可以同时运行(而不采取copy多个Tomcat的副本的方法)

每个Tomcat实例的私有文件夹:(conf配置文件,logs日志,webapps自己的app目录,work自己的临时工作区间,temp存放JVM的临时文件)

  • conf - Server configuration files (including server.xml)
  • logs - Log and output files
  • webapps - Automatically loaded web applications
  • work - Temporary working directories for web applications
  • temp - Directory used by the JVM for temporary files (java.io.tmpdir)

2. 同时运行多个Tomcat实例的正确姿势

  1. 找到Tomcat的安装目录,然后把Tomcat的私有工作目录全部拷贝到新的(每个Tomcat实例文件夹下)

    私有工作目录如下:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0RoI3Mzj-1570847392385)(D:\my_heart_note\tomcat\笔记\Tomcat.assets\1569894952277.png)]

    拷贝到Tomcat实例文件夹下:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RDZepeP4-1570847392387)(D:\my_heart_note\tomcat\笔记\Tomcat.assets\1569894978489.png)]

创建bin目录:bin目录下创建新的startup.bat启动脚本,和把tomcat-juli.jar拷贝过来

startup.bat简易写法如下:(主要是配置CATALINA_HOME和CATALINA_BASE)

set "TITLE=Tomcat9-1"
cd..
set "CATALINA_BASE=%cd%"
set "CATALINA_HOME=D:\my_heart_note\tomcat\apache-tomcat-9.0.26"
set "EXECUTABLE=%CATALINA_HOME%\bin\catalina.bat"

CALL %EXECUTABLE% start
set "TITLE=Tomcat9-2"
cd..
set "CATALINA_BASE=%cd%"
set "CATALINA_HOME=D:\my_heart_note\tomcat\apache-tomcat-9.0.26"
set "EXECUTABLE=%CATALINA_HOME%\bin\catalina.bat"

CALL %EXECUTABLE% start

TITLE是设置Tomcat窗口名字

还要修改端口号:三个端口号(Shutdown的,connector的,AJP的)

引发的各个问题解决

  1. 引发了窗口的乱码问题:因为我们窗口名字默认为Tomcat,但是到了我们的多个Tomcat实例的时候,窗口名字就不默认了。所以手动设置TITLE;

  2. 然后我想要实现的是修改Tomcat窗口的字符集。而不是修改Tomcat打印日志的字符集,去适应Windows的gbk;而是适应我们的UTF-8

  3. 所以决定修改Windows对于某个窗口的字符集。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B8Qnm7RC-1570847392388)(D:\my_heart_note\tomcat\笔记\Tomcat.assets\1569895509349.png)]

十进制修改为65001

左侧Console下面的项为窗口名字,如:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZzSc1SDT-1570847392389)(D:\my_heart_note\tomcat\笔记\Tomcat.assets\1569895545382.png)]

效果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A8xGEAMv-1570847392391)(D:\my_heart_note\tomcat\笔记\Tomcat.assets\1569895773026.png)]

厉害吧!

上面的效果是我修改了每个Tomcat实例中的webapp里的ROOT文件夹里的index.jsp首页的title

原理是

在每个Tomcat实例中的conf配置文件中,web.xml配置了一些关于应用处理的信息(Servlet相关配置)

    <servlet>
        <!--DefaultServlet-->
        <servlet-name>default</servlet-name>
        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <init-param>
            <param-name>listings</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet>
    	<!--JSPServlet-->
        <servlet-name>jsp</servlet-name>
        <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
        <init-param>
            <param-name>fork</param-name>
            <param-value>false</param-value>
        </init-param>
        <init-param>
            <param-name>xpoweredBy</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>3</load-on-startup>
    </servlet>

mapping

    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <!--处理每个 根 请求/-->
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    <!-- The mappings for the JSP servlet -->
    <servlet-mapping>
        <servlet-name>jsp</servlet-name>
        <url-pattern>*.jsp</url-pattern>
        <url-pattern>*.jspx</url-pattern>
    </servlet-mapping>

  <!-- ==================== Default Welcome File List ===================== -->
  <!-- When a request URI refers to a directory, the default servlet looks  -->
  <!-- for a "welcome file" within that directory and, if present, to the   -->
  <!-- corresponding resource URI for display.                              -->
  <!-- If no welcome files are present, the default servlet either serves a -->
  <!-- directory listing (see default servlet configuration on how to       -->
  <!-- customize) or returns a 404 status, depending on the value of the    -->
  <!-- listings setting.                                                    -->
  <!--                                                                      -->
  <!-- If you define welcome files in your own application's web.xml        -->
  <!-- deployment descriptor, that list *replaces* the list configured      -->
  <!-- here, so be sure to include any of the default values that you wish  -->
  <!-- to use within your application.                                       -->

    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

意思是如果没有精准匹配到的Servlet,就会走DefaultServlet,就会调用到welcome-file-list中的网页

3. Tomcat server.xml中体现出来的架构图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OklaP7Fh-1570847392393)(D:\my_heart_note\tomcat\笔记\Tomcat.assets\1569909095997.png)]

<Server port="9005" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />

  <!-- A "Service" is a collection of one or more "Connectors" that share
       a single "Container" Note:  A "Service" is not itself a "Container",
       so you may not define subcomponents such as "Valves" at this level.
       Documentation at /docs/config/service.html
   -->
   //提供的一种服务Service:名字为Catalina
  <Service name="Catalina">

      //这个服务下有多个连接器Connector,可以连接这个服务
    <Connector port="9090" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
    <!-- Define an AJP 1.3 Connector on port 8009 -->
    <Connector port="9009" protocol="AJP/1.3" redirectPort="8443" />

      //这个Service的底层由Engine支持,Engine里由主机或者虚拟主机构成
      (提供应用webapp支持)
      
    <Engine name="Catalina" defaultHost="localhost">
      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
      </Realm>
        //Host主机(或者在这里配置虚拟主机也可以,name为主机名,appBase为webapp目录的路径
      <Host name="localhost"  appBase="webapps"
            //unpackWARs:是否解压War包;//autoDeploy是否自动部署(热部署,一放上去就自动部署,发布)
            unpackWARs="true" autoDeploy="true">

        <!-- Access log processes all example.
             Documentation at: /docs/config/valve.html
             Note: The pattern used is equivalent to using pattern="common" -->
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log" suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />

      </Host>
    </Engine>
  </Service>
</Server>

4. 配置虚拟目录

虚拟目录:映射到别的文件夹中

比如我们想127.0.0.1/blog/index 和 127.0.0.1/sky_chou/index

表现是:两个webapp目录blog和sky_chou,然后webapp里有各自的app应用

而不是把所有的app都部署在同一个webapp下(同时还能实现修改域名的功能)

原理是把域名请求 映射到 docBase配置的映射路径下。

(缺点:要重启服务器)

第一种方法 - 修改server.xml

在HOST标签里,添加<Context path="请求访问路径(基于上一级的Host) docBase=“映射的webapp路径” />

第二种方法 - 修改conf文件夹里的虚拟主机文件夹(里的*.xml)

原理:因为Tomcat会为每个服务 在conf文件夹中创建这个服务的配置文件

如:Service里的Catalina服务

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5Vz0GijA-1570847392394)(D:\my_heart_note\tomcat\笔记\Tomcat.assets\1569930181265.png)]

conf里有Catalina文件夹

里面有Host主机的文件夹:localhost

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IzSrgW1Z-1570847392396)(D:\my_heart_note\tomcat\笔记\Tomcat.assets\1569930215980.png)]

我们想要完成热部署(不重启就能实现虚拟主机的映射),创建一个*.xml ( *就是path属性)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uhNVzwhT-1570847392397)(D:\my_heart_note\tomcat\笔记\Tomcat.assets\1569930236394.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WYBNBrMM-1570847392399)(D:\my_heart_note\tomcat\笔记\Tomcat.assets\1569930281658.png)]

调用的姿势:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ErMCY0D9-1570847392400)(D:\my_heart_note\tomcat\笔记\Tomcat.assets\1569930297748.png)]

注意:这个blog目录并不在原来的webapps里,而是在自己配置的目录中

5. 配置虚拟主机

只是用来模拟一台主机上,可以通过多个域名去访问不同的webapp应用(从而达到区分)

但是实际上(域名是需要DNS解析服务的)

实际上我们可以实现:通过注册自己的多个域名,然后在Tomcat上配置对应的域名 和虚拟主机

方法:添加HOST

6. Tomcat的目录结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HIa6dx7c-1570847392402)(D:\my_heart_note\tomcat\笔记\Tomcat.assets\1569978452956.png)]

bin:是很多脚本(包括windows,linux适用的)和一些jar包,以及exe可执行的tomcat应用程序

conf:是配置文件所存放的地方:有server.xml(Tomcat服务器的配置),web.xml(默认的web应用配置信息,比如一些默认的Servlet,以及JSPServlet)。

tomcat-users.xml (Tomcat用户权限管理)

lib目录:存放了很多加载所需要的jar包

logs:日志存放的地方

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LyVhzUKU-1570847392402)(D:\my_heart_note\tomcat\笔记\Tomcat.assets\1569978781635.png)]

catalina:是访问了这个catalina服务的日志记录。(包含了详细的日志信息和报错信息)

localhost_access_log : 记录了访问这个主机的所有请求以及HTTP状态码等信息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oM6agjti-1570847392404)(D:\my_heart_note\tomcat\笔记\Tomcat.assets\1569978884347.png)]

7. Tomcat源码部署

首先下载源码,解压到某个文件夹

然后以此,构建Maven项目。通过POM文件引入启动Tomcat仍需要的Jar包

以及相关文件夹的移动

然后创建Main启动类为Bootstrap

配置JVM启动参数

修改源码(初始化JSP解析器)

在ContextConfig类中的configureStart方法里,在webConfig()后面添加,初始化JSP解析器

    protected synchronized void configureStart() {
   
        // Called from StandardContext.start()

        if (log.isDebugEnabled()) {
   
            log.debug(sm.getString("contextConfig.start"));
        }

        if (log.isDebugEnabled()) {
   
            log.debug(sm.getString("contextConfig.xmlSettings",
                    context.getName(),
                    Boolean.valueOf(context.getXmlValidation()),
                    Boolean.valueOf(context.getXmlNamespaceAware())));
        }

        webConfig();
        //初始化JSP解析器
        context.addServletContainerInitializer(new JasperInitializer(),null);

pom文件

<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.apache.tomcat</groupId>
    <artifactId>apache-tomcat-9.0-src</artifactId>
    <version>1.0-SNAPSHOT</version>

    <build>
        <finalName>Tomcat9.0</finalName>
        <sourceDirectory>src/main/java</sourceDirectory>
        <resources>
            <resource>
                <directory>src/main/java</directory>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <encoding>UTF-8</encoding>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.easymock</groupId>
            <artifactId>easymock</artifactId>
            <version>3.4</version>
        </dependency>
        <dependency>
            <groupId>ant</groupId>
            <artifactId>ant</artifactId>
            <version>1.7.0</version>
        </dependency>
        <dependency>
            <groupId>wsdl4j</groupId>
            <artifactId>wsdl4j</artifactId>
            <version>1.6.2</version>
        </dependency>
        <dependency>
            <groupId>javax.xml</groupId>
            <artifactId>jaxrpc</artifactId>
            <version>1.1</version>
        </dependency>
        <dependency>
            <groupId>org.eclipse.jdt.core.compiler</groupId>
            <artifactId>ecj</artifactId>
            <version>4.6.1</version>
        </dependency>
    </dependencies>
</project>

注意:Tomcat 9 里面的JDTCompiler源码里有CompilerOptions.VERSION_1_9这种高于1.9版本的,如果没有安装这些版本的话,识别不了

Tomcat9中有部分代码使用CompilerOptions.VERSION_1_9来判断java虚拟机版本,里面涉及1.9版本的jvm,我机器上识别不了。

java/org/apache/jasper/compiler/JDTCompiler.java类中把上述代码找出,删除即可,总共有3处。

参考链接:https://blog.csdn.net/linxdcn/article/details/72811928

8. 为什么用源码启动Tomcat 9的时候,控制台输出的中文全部都是乱码

如何发现编码是哪种乱码所导致的呢?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S4OBaPFd-1570847392405)(D:\my_heart_note\tomcat\笔记\Tomcat.assets\1570003119787.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uDI0VcEm-1570847392406)(D:\my_heart_note\tomcat\笔记\Tomcat.assets\1570003125879.png)]

一步步debug的过程找寻原因:

  1. [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HOmcuZVo-1570847392407)(D:\my_heart_note\tomcat\笔记\Tomcat.assets\1570002765099.png)]

  2. 找到这个国际化配置文件

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TNKIMBcw-1570847392408)(D:\my_heart_note\tomcat\笔记\Tomcat.assets\1570002802066.png)]

  3. 继续debug下去,sm.getString()底层调用的ResourceBundle实现类去读取的Properties文件

    我们看下面的文档注释(知道ResourceBundle只会按ISO8859-1去读取,要想读取非ISO8859-1编码的内容,需要以UNICODE形式去填写properties文件。

 * <p>
 * The implementation of a {
   @code PropertyResourceBundle} subclass must be
 * thread-safe if it's simultaneously used by multiple threads. The default
 * implementations of the non-abstract methods in this class are thread-safe.
 *
 * <p>
 * <strong>Note:</strong> PropertyResourceBundle can be constructed either
 * from an InputStream or a Reader, which represents a property file.
 * Constructing a PropertyResourceBundle instance from an InputStream requires
 * that the input stream be encoded in ISO-8859-1.  In that case, characters
 * that cannot be represented in ISO-8859-1 encoding must be represented by Unicode Escapes
 * as defined in section 3.3 of
 * <cite>The Java&trade; Language Specification</cite>
 * whereas the other constructor which takes a Reader does not have that limitation.
  1. 效果如下:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T70Jpttl-1570847392410)(D:\my_heart_note\tomcat\笔记\Tomcat.assets\1570002943894.png)]

9. Tomcat整体架构

img

9.1 Http工作原理

客户端->服务端(在浏览器输入url)

用的是HTTP协议

所以在传输层先通过TCP协议与服务器建立三次握手

连接完成后,客户端再封装请求数据为HTTP报文格式

然后从高层往底层封装,传输到服务器那边去。

服务器拆包,解析HTTP报文。

然后服务端调用服务器软件程序去处理这个HTTP请求,(比如Tomcat,调用不同的Servlet去处理请求)

然后把响应数据封装成HTTP报文,再传回去。

9.2 Servlet容器工作流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YQfaHx7A-1570847392412)(D:\my_heart_note\tomcat\笔记\Tomcat.assets\1570004188277.png)]

为了解耦,HTTP服务器并不直接调用Servlet去处理每个用户请求。而是交给了更为专业的Servlet容器(Tomcat)去处理请求。

首先,把用户请求的HTTP报文,解析封装成一个ServletRequest对象,然后传给Servlet容器,根据这个对象里的url,通过事先在(web.xml或者注解上定义的映射关系),找到对应的Servlet进行处理。(这里利用了反射技术,动态地创建相应的Servlet)

把ServletRequest传给Servlet之后,Servlet再调用核心方法Service()进行逻辑的处理,根据不同的请求格式,如POST,GET分别处理(doPost(),doGet() )

然后再把响应信息封装到servletResponse对象中,最后通过HTTP服务的处理,加上响应头,封装成HTTP报文传回给客户端。

9.3 Tomcat整体架构-两大组件

从宏观上来看,且从数据流转的角度来看,Tomcat最外面的两个核心组件就是Connector连接器和Container容器

  1. Connector:负责处理Socket请求,然后把请求数据封装成Request对象;还把Response中的响应数据封装成HTTP报文返回给客户端。(相当于HTTP服务器,不处理具体的逻辑业务,只负责转发和接收)

  2. Container容器(Servlet容器):主要是拿到Connector传过来的Request对象,通过解析里面的url,

    找到对应的Servlet进行处理。先检查这个Servlet是否已经加载(如果加载过了,就直接用),没有加载过的话,就通过反射进行创建);所以从这里可以看得出来Servlet是单例的。

    然后Servlet调用Service()方法进行处理,把响应数据封装成Response对象传回给Connector

(中间还要经过catalina容器)

(Catalina容器接收的是ServletRequest对象)

(所以在Connector组件和Catalina之间还有好多组件)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TLRrZZWo-1570847392413)(D:\my_heart_note\tomcat\笔记\Tomcat.assets\1570005479858.png)]

解耦!

9.4 Connector组件的IO模型

应用层协议

HTTP/1.1 AJP(Apache服务器) HTTP/2.0

传输层

NIO(非阻塞IO) NIO2.0(异步IO,JDK7.0后支持) APR(C/C++网络通讯库)

“阻塞”与"非阻塞"与"同步"与“异步"不能简单的从字面理解,提供一个从分布式系统角度的回答。
1.同步与异步
同步和异步关注的是消息通信机制 (synchronous communication/ asynchronous communication)
所谓同步,就是在发出一个调用时,在没有得到结果之前,该调用就不返回。但是一旦调用返回,就得到返回值了。
换句话说,就是由调用者主动等待这个调用的结果。

而异步则是相反,调用*在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在调用*发出后,被调用者通过状态、通知来通知调用者,或通过回调函数处理这个调用。

典型的异步编程模型比如Node.js

举个通俗的例子:
你打电话问书店老板有没有《分布式系统》这本书,如果是同步通信机制,书店老板会说,你稍等,”我查一下",然后开始查啊查,等查好了(可能是5秒,也可能是一天)告诉你结果(返回结果)。
而异步通信机制,书店老板直接告诉你我查一下啊,查好了打电话给你,然后直接挂电话了(不返回结果)。然后查好了,他会主动打电话给你。在这里老板通过“回电”这种方式来回调。

\2. 阻塞与非阻塞
阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态.

阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。
非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。

还是上面的例子,
你打电话问书店老板有没有《分布式系统》这本书,你如果是阻塞式调用,你会一直把自己“挂起”,直到得到这本书有没有的结果,如果是非阻塞式调用,你不管老板有没有告诉你,你自己先一边去玩了, 当然你也要偶尔过几分钟check一下老板有没有返回结果。
在这里阻塞与非阻塞与是否同步异步无关。跟老板通过什么方式回答你结果无关。

如果是关心阻塞 IO/ 异步 IO, 参考 Unix Network Programming View Book

还是2014年写的以解释概念为主,主要是同步异步 阻塞和非阻塞会被用在不同层面上,可能会有不准确的地方,并没有针对 阻塞 IO/ 异步 IO 等进行讨论,大家可以后续看看这两个回答:

怎样理解阻塞非阻塞与同步异步的区别?

怎样理解阻塞非阻塞与同步异步的区别?

9.5 Connector重要组件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sGXMV2JV-1570847392414)(D:\my_heart_note\tomcat\笔记\Tomcat.assets\1570009028902.png)]

Endpoint:Coyote的通信断点,是具体Socket接收和发送处理器,是对传输层的抽象,因此,Endpoint是用来实现TCP/IP协议的。

Tomcat没有Endpoint接口,而是定义了AbstractEndpoint,里面定义了两个内部类:Acceptor和SocketProcessor

Acceptor用来监听Socket请求,SocketProcessor用来处理接收到的Socket请求,它实现了Runnable接口

 /**
     * Thread used to accept new connections and pass them to worker threads.
     */
    protected Acceptor<U> acceptor;

在run()方法里调用协议处理组件Processor进行处理。为了提高处理能力,SocketProcessor被提交到线程池执行,这个线程池叫Executor。Tomcat扩展了原生的Java线程池。java.concurrent包下的。

    protected abstract SocketProcessorBase<S> createSocketProcessor(
            SocketWrapperBase<S> socketWrapper, SocketEvent event);

这是抽象类SocketProcessorBase

    @Override
    public final void run() {
   
        synchronized (socketWrapper) {
   
            if (socketWrapper.isClosed()) {
   
                return;
            }
            doRun();
        }
    }

这是NIOEndpoint的内部类SocketProcessor

    // ---------------------------------------------- SocketProcessor Inner Class

    /**
     * This class is the equivalent of the Worker, but will simply use in an
     * external Executor thread pool.
     */
    protected class SocketProcessor extends SocketProcessorBase<NioChannel> {
   

        public SocketProcessor(SocketWrapperBase<NioChannel> socketWrapper, SocketEvent event) {
   
            super(socketWrapper, event);
        }

        @Override
        protected void doRun() {
   
            NioChannel socket = socketWrapper.getSocket();
            SelectionKey key = socket.getIOChannel().keyFor(socket.getSocketWrapper().getPoller().getSelector());
            Poller poller = NioEndpoint.this.poller;
            if (poller == null) {
   
                socketWrapper.close();
                return;
            }

            try {
   
                int handshake = -1;

                try {
   
                    if (key != null) {
   
                        if (socket.isHandshakeComplete()) {
   
                            // No TLS handshaking required. Let the handler
                            // process this socket / event combination.
                            handshake = 0;
                        } else if (event == SocketEvent.STOP || event == SocketEvent.DISCONNECT ||
                                event == SocketEvent.ERROR) {
   
                            // Unable to complete the TLS handshake. Treat it as
                            // if the handshake failed.
                            handshake = -1;
                        } else {
   
                            handshake = socket.handshake(key.isReadable(), key.isWritable());
                            // The handshake process reads/writes from/to the
                            // socket. status may therefore be OPEN_WRITE once
                            // the handshake completes. However, the handshake
                            // happens when the socket is opened so the status
                            // must always be OPEN_READ after it completes. It
                            // is OK to always set this as it is only used if
                            // the handshake completes.
                            event = SocketEvent.OPEN_READ;
                        }
                    }
                } catch (IOException x) {
   
                    handshake = -1;
                    if (log.isDebugEnabled()) log.debug("Error during SSL handshake",x);
                } catch (CancelledKeyException ckx) {
   
                    handshake = -1;
                }
                if (handshake == 0) {
   
                    SocketState state = SocketState.OPEN;
                    // Process the request from this socket
                    if (event == null) {
   
                        state = getHandler().process(socketWrapper, SocketEvent.OPEN_READ);
                    } else {
   
                        state 
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值