tomcat 黑马学习笔记

Tomcat概述

1、怎么描述tomcat?

Servlet规范把能够发布和运行Javaweb应用的web服务器称为’Servlet容器’,因此,可以理解为Tomcat就是一个servlet容器。

常见的web服务器(servlet容器)

  • webLogic:oracle公司,大型的JavaEE服务器,支持所有的JavaEE规范,收费的。
  • webSphere:IBM公司,大型的JavaEE服务器,支持所有的JavaEE规范,收费的。
  • JBOSS:JBOSS公司的,大型的JavaEE服务器,支持所有的JavaEE规范,收费的。
  • Tomcat:Apache基金组织,中小型的JavaEE服务器,仅仅支持少量的JavaEE规范 servlet/jsp。开源的,免费的。

2、tomcat作为servlet容器的基本功能:

就是负责接收和解析来自客户的请求,同时把客户的请求传送给响应的servlet,并把servlet的响应结果返回给客户。

在这里插入图片描述

3、Servlet规范规定,Servlet容器 接收请求访问特定Servlet的流程

  1. 客户发出访问特定Servlet的请求
  2. Servlet容器接收客户请求,解析请求
  3. Servlet容器创建一个ServletRequest对象,其包含客户所有请求信息。如请求头,请求正文,客户端IP地址等
  4. Servlet容器创建一个ServletResponse对象
  5. Servlet容器调用客户请求的Servlet的service()服务方法,并且把ServletRequest对象和ServletResponse对象作为参数传给该方法。
  6. Servlet从ServletRequest对象获取客户的请求信息
  7. Servlet利用ServletResponse对象生成响应结果
  8. Servlet容器把Servlet生成的响应结果发送给客户
     

4、tomcat的目录结构

5、tomcat处理http服务请求

servlet容器以及servlet接口,是用来实现http服务器和业务类之间的解耦。(servlet接口和servlet容器这一套规范叫做servlet规范)

tomcat按照servlet规范的要求实现了servlet容器,具有HTTP服务器的功能,提供http访问的统一入口。

在这里插入图片描述

6、tomcat两个核心组件

连接器 --》对外

容器 --》对内

7、coyote连接器简介

coyote是tomcat连接器框架的名称,是tomcat提供的供客户端访问的外部接口,客户端通过coyote与服务器建立连接,发送请求并接收响应 。

coyote底层封装了底层的网络通信(支持socket请求以及响应的处理),为catalina容器提供了统一的接口,是的catalina容器与具体的请求协议和IO操作方式完全解耦。

coyote将socket输入转换封装成request对象,交给catalina处理,处理完成后,通过coyote提供的response对象将结果写入输出流。

coyote作为独立的模块,只负责具体的协议和IO相关的操作,和servlet规范的实现没有直接关系,coyote生成的response和request 是通过CoyoteAdapter的service方法进一步封装servletReuqest  和 servletResponse

8、coyote中的IO模型和协议

IO模型,自8.5版本起,tomcat传输层移除了对BIO的支持,默认协议是NIO

应用层协议

tomcat为了实现支持多种IO模型和应用层协议,一个容器可以对应多个连接器(如6中的图),单独的容器或者连接器不能对外提供服务,需要组装起来才可以工作,组装后的整体叫做service组件。tomcat支持配置多个service,这样可以实现通过不同端口号来访问同一台机器上部署的不同应用。

9、coyote中的组件

1、endpoint:

通信端点,就是监听通信的端口,是具体的socket接收和发送处理器,endpoint用来实现TCP/IP协议。 Tomcat 并没有EndPoint 接口,而是提供了一个抽象类AbstractEndpoint (NioEndpoint ,Nio2Endpoint ,AprEndpoint 都继承了AbstractEndpoint) ---tomcat10.1.1源码没看到AprEndpoint

在AbstractEndpoint类中,重点关注两个内部类 (Acceptor和SocketProcessor)

1、Acceptor(tomcat10.1.1中这个已经不是内部类了)

Acceptor用于监听socket请求,代码在run()方法中

2、SocketProcessor

SocketProcessor用于处理接收到的Socket请求,它实现Runnable接口,在Run方法里 调用协议处理组件Processor进行处理。为了提高处理能力,SocketProcessor被提交到线程池来执行。而这个线程池叫作执行器(Executor)

2、processer: coyote协议处理接口

简单来说:EndPoint是用来实现TCP/IP协议;Processor用来实现HTTP协议

Processor接收来自EndPoint的Socket,读取字节流解析成Tomcat Request和Response对象,并通过Adapter将其提交到容器处理, Processor是对应用层协议的抽象。

 3、ProtocolHandler : Coyote 协议接口

ProtocolHandler: Coyote 协议接口, 通过Endpoint 和 Processor , 实现针对具体协议的处理能力。

Tomcat 按照协议和I/O 提供了6个实现类 :

  • AjpNioProtocol
  • AjpAprProtocol (tomcat10.1.1中没有看到)
  • AjpNio2Protocol
  • Http11NioProtocol
  • Http11Nio2Protocol
  • Http11AprProtocol(tomcat10.1.1中没有看到)

通过Service标签中连接器Connector 的属性 protocol="HTTP/1.1 指定协议名称

 <Service name="Catalina">
    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
    
    <Connector executor="tomcatThreadPool"
               port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
   
    <Connector protocol="AJP/1.3"
               address="::1"
               port="8009"
               redirectPort="8443" />
  </Service>

 4、Adapter

adapter负责将request,response 转换为 servletRequest, servletResponse

调用的是CoyoteAdapter中的service方法,对请求进行解析适配后,调用容器,其中getcontianer()返回的就是Engine对象。

10、tomcat中的容器,catalina概述

Tomcat 本质上就是一款 Servlet 容器, 因此Catalina 才是 Tomcat 的核心 , 其他模块都是为Catalina 提供支撑的。

  • 通过Coyote 模块提供链接通信
  • Jasper 模块提供JSP引擎
  • Naming 提供JNDI 服务
  • Juli 提供日志服务。

 11、Catalina简介,其组件的职责

Catalina负责管理Server,而Server表示着整个服务器。Server下面有多个服务Service,每个服务都包含着多个连接器组件ConnectorCoyote 实现)和一个容器组件Container。在Tomcat 启动的时候, 会初始化一个Catalina的实例。 在这里插入图片描述

 

 12、container容器的结构

Tomcat设计了4种容器,分别是Engine、Host、Context和Wrapper。这4种容器不是平行关系,而是父子关系。 Tomcat通过一种分层的架构,使得Servlet容器具有很好的灵活性。

 Tomcat 采用了组件化的设计,它的构成组件都是可配置的,其中最外层的是Server,其他组件 按照一定的格式要求配置在这个顶层容器中。这些可以在配置文件server.xml中进行配置

 13、tomcat如何管理定义的四种容器?

所有容器组件都实现了Container接口,因此组合模 式可以使得用户对单容器对象和组合容器对象的使用具有一致性。这里单容器对象指的是最底层的Wrapper,组合容器对象指的是上面的Context、Host或者Engine。

Container接口中有parent/child相关的方法,用于标识父子关系。

此外,Container接口扩展了LifeCycle接口,LifeCycle接口用来统一管理各组件的生命周期。

在这里插入图片描述

 

 14、tomcat启动流程

在这里插入图片描述

总结:初始化或者启动父组件自身,然后调用子组件。----> 加载Tomcat的配置文件,初始化容器组件,监听对应的端口,准备接受客户端的请求。

启动步骤:

  • 启动tomcat , 需要调用 bin/startup.bat (在linux 目录下 , 需要调用 bin/startup.sh) , 在startup.bat 脚本中, 调用了catalina.bat。
  • 在catalina.bat 脚本文件中,调用了BootStrap 中的main方法。
  • 在BootStrap 的main 方法中调用了 init 方法 , 来创建Catalina 及 初始化类加载器。
  • 在BootStrap 的main 方法中调用了 load 方法 , 在其中又调用了Catalina的load方 法。
  • 在Catalina 的load 方法中 , 需要进行一些初始化的工作, 并需要构造Digester 对象, 用 于解析 XML。
  • 然后在调用后续组件的初始化操作 。。。 加载Tomcat的配置文件,初始化容器组件 ,监听对应的端口号, 准备接受客户端请求。

 15、tomcat中各个组件的默认实现类

在这里插入图片描述

接口默认实现
ServerStanderdServer
ServiceStanderdService
EngineStanderdEngine
HostStanderdHost
ContextStanderdContext
Endpoint提供一个抽象类AbstractEndpoint
Processor

见图

ProtocolHandler封装endpoint和processor,实现对具体协议的处理功能

16、tomcat的请求处理流程

tomcat中,Mapper组件实现了将用户请求的URL定位到一个Servlet的功能。使得tomcat实现每个请求都可以精准的找到对应的servlet。

Mapper组件工作原理:

Mapper组件里保存了Web应用的配置信息,其实就是容器组件与访问路径的映射关系,比如Host容器里配置的域名、Context容器里的Web应用路径,以及Wrapper容器里Servlet映射的路径,你可以想象这些配置信息就是一个多层次的Map。

当一个请求到来时,Mapper组件通过解析请求URL里的域名和路径,再到自己保存的Map里去查找,就能定位到一个Servlet。请你注意,一个请求URL最后只会定位到一个Wrapper容器,也就是一个Servlet。

在这里插入图片描述

具体步骤:

  1. Connector组件Endpoint中的Acceptor监听客户端套接字连接并接收Socket。
  2. 将连接交给线程池Executor处理,开始执行请求响应任务。
  3. Processor组件读取消息报文,解析请求行、请求体、请求头,封装成Request对象。
  4. Mapper组件根据请求行的URL值和请求头的Host值匹配由哪个Host容器、Context容器、Wrapper容器处理请求。
  5. CoyoteAdaptor组件负责将Connector组件和Engine容器关联起来,把生成的Request对象和响应对象Response传递到Engine容器中,调用 Pipeline。
  6. Engine容器的管道开始处理,管道中包含若干个Valve、每个Valve负责部分处理逻辑。执行完Valve后会执行基础的 Valve–StandardEngineValve,负责调用Host容器的Pipeline。
  7. Host容器的管道开始处理,流程类似,最后执行 Context容器的Pipeline。
  8. Context容器的管道开始处理,流程类似,最后执行 Wrapper容器的Pipeline。
  9. Wrapper容器的管道开始处理,流程类似,最后执行 Wrapper容器对应的Servlet对象的处理方法。
    在这里插入图片描述

         在Tomcat中定义了Pipeline 和 Valve 两个接口,Pipeline 用于构建责任链, Valve代表责任链上的每个处理器。Pipeline 中维护了一个基础的Valve,它始终位于Pipeline的末端(最后执行),封装了具体的请求处理和输出响应的过程。当然,我们也可以调用addValve()方法, 为Pipeline 添加其他的Valve, 后添加的Valve 位于基础的Valve之前,并按照添加顺序执行。Pipiline通过获得首个Valve来启动整合链条的执行 。

17、tomcat中的Jasper简介

JSP页面中编写 Java代码,添加第三方的标签库,以及使用EL表达式。但是无论经过何种形式的处理,最终输出到客户端的都是标准的HTML页面(包含js ,css…),并不包含任何的java相关的语法。 故jsp看做是一种运行在服务端的脚本。

服务器如何将 JSP页面转换为HTML页面?

Jasper模块是Tomcat的JSP核心引擎,JSP本质上是一个Servlet。Tomcat使用Jasper对JSP语法进行解析,生成Servlet并生成Class字节码,用户在进行访问jsp时,会访问Servlet,最终将访问的结果直接响应在浏览器端 。另外,在运行的时候,Jasper还会检测JSP文件是否修改,如果修改,则会重新编译JSP文件。

18、JSP的编译方式

tomcat并不会在启动web程序的时候自动编译jsp文件,而是在客户端第一次请求时,才编译需要访问的jsp文件。(如果安装了Apache Ant,则可以使用ant进行预编译)

当容器启动时,会读取在webapps目录下所有的web应用中的web.xml文件,然后对xml文件进行解析,并读取servlet注册信息。然后,将每个应用中注册的servlet类都进行加载,并通过反射的方式实例化(Tomcat 创建servlet类实例的方法和原理)

Tomcat 在默认的web.xml 中配置了一个**org.apache.jasper.servlet.JspServlet**,用于处理所有的**.jsp **** .jspx **结尾的请求,该Servlet 实现即是运行时编译的入口。

   <servlet>
        <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>

    <!-- The mapping for the default servlet -->
    <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>

 编译过程:

1、调用JspServlet的service方法,里面会获取jsp文件路径,如果界面没有传,会根据配置文件配置的servlet-mapping进行查找(上面xml里面有写)

判断当前请求是否是预编译请求,然后执行serviceJspFile()方法

/

2、 在serviceJspFile()方法中获取JspServletWrapper,然后调用JspServletWrapper的service方法

3 、 若是第一次调用,则需要编译,在JspServletWrapper的service方法中通过调用JspCompilationContext的compile()方法,在调用Compiler的compile()方法,生成Java文件和class文件。 

4 、生成文件之后,JspServletWrapper的service方法加载编译并实例化之后的servlet,然后调用其service()方法,这个service方法就是编译生成的service方法。

编译结果:

1、如果在 tomcat/conf/web.xml 中配置了参数scratchdir , 则jsp编译后的结果,就会存储在该目录下。

<init-param>
     <param-name>scratchdir</param-name>
     <param-value>D:/tomcat-temp</param-value>
 </init-param>

2、如果没有配置该选项, 则会将编译后的结果,存储在Tomcat安装目录下的work/Catalina(Engine名称)/localhost(Host名称)/Context名称

3、如果使用的是 IDEA 开发工具集成Tomcat 访问web工程中的jsp , 编译后的结果,存放在 :C:\Users\用户名\AppData\Local\JetBrains\IntelliJIdea2020.1\tomcat\Unnamed_Tomcat8_0\work\Catalina\localhost\jsp_demo\org\apache\jsp

19、Jasper编译文件简介。

分析:

  1. 编译后的类继承自 org.apache.jasper.runtime.HttpJspBase,是HttpServlet的子类,因此jsp本质上就是一个servlet
  2. 通过属性 _jspx_dependants 保存了当前JSP页面依赖的资源, 包含引入的外部的JSP页面、导入的标签、标签所在的jar包等,便于后续处理过程中使用(如重新编译检测, 因此它以Map形式保存了每个资源的上次修改时间)。
  3. 通过属性 _jspx_imports_packages 存放导入的 java 包, 默认导入 javax.servlet ,javax.servlet.http, javax.servlet.jsp 。
  4. 通过属性 _jspx_imports_classes 存放导入的类, 通过import 指令导入的DateFormat 、SimpleDateFormat 、Date 都会包含在该集合中。_jspx_imports_packages 和 _jspx_imports_classes 属性主要用于配置 EL 引擎上下文。
  5. 请求处理由方法 _jspService 完成 , 而在父类 HttpJspBase 中的service 方法通过模板方法模式 , 调用了子类的 _jspService 方法。
  6. _jspService 方法中定义了几个重要的局部变量 : pageContext 、Session、application、config、out、page。由于整个页面的输出有 _jspService 方法完成,因此这些变量和参数会对整个JSP页面生效。 这也是我们为什么可以在JSP页面使用这些变量的原因。
  7. 指定文档类型的指令 (page) 最终转换为 response.setContentType() 方法调用。
  8. 对于每一行的静态内容(HTML) , 调用 out.write 输出。
  9. 对于 <% … %> 中的java 代码 , 将直接转换为 Servlet 类中的代码。 如果在 Java代码中嵌入了静态文件, 则同样调用 out.write 输出。

Tomcat 配置文件

tomcat服务器的主要配置文件都集中在tomcat/conf目录下

1、server.xml

server.xml是tomcat的核心配置文件,包含了servlet容器的所有配置,下面列举一些重要的配置。

1.1 Server

Server是server.xml的根元素,用于创建一个server实例,代码里的默认实现类是StandarServer。

port:tomcat监听的关闭服务器的端口,默认9005,建议改成-1,即关闭该端口

shutdown:关闭服务器的指令字符串,建议修改。

<Server port="9005" shutdown="SHUTDOWN">
。。。
</Server>

Server内嵌的子元素为:Listener(监听器),GlobalNamingResources(全局命名),Service

1.2 Service

用于创建Service实例,代码默认使用StandarService,默认情况下,tomcat仅仅指定了Service的名称“Catalina”, Service可以内嵌的元素包括

  • Listener:为Service添加生命周期监听器
  • Executor: 配置Service共享线程池
  • Connector: 配置Service包含的连接器
  • Engine: 配置Service中连接器对应的servlet容器引擎

1.3 Executor

默认情况下,Service没有添加共享线程池配置,catalina各个组件在用到线程池时会独立创建

如果想要配置共享线程成,可以在<Service>下添加如下配置

在这里插入图片描述

1.4 Connector

 Connector用于创建连接器实例,默认情况下,server.xml配置了两个连接器,一个支持HTTP协议,一个支持AJP协议,因此大多数情况下,不需要新增连接器配置,只根据自己需要对已有的连接器进行优化即可。

  •  port:端口号,Connector用于创建服务端socket并进行监听客户端的请求连接,如果端口号设置为0,则tomcat会随机选用一个可用的端口号给当前Connector使用
  • protocol:当前Connector支持的访问协议,默认是HTTP/1.1,并采用自动切换机制,选择一个机遇Java NIO 的连接器或者机遇本地APR的连接器(这个也要看是否含有tomcat的本地库),如果不希望自动切换,可以明确指定协议(如:org.apache.coyote.http11.Http11NioProtocol)
  • connectionTimeout:Connector接收链接请求后的等待超时时间,单位为毫秒,-1表示不超时。
  • redirectPort:当前Connector不支持SSL请求,接收到的请求符合security-constraint约束,需要SLL传输,catalina会自动将请求重定向到指定的端口。
  • excutor:指定共享线程池的名称,也可以通过maxThreads、minSpareThreads等属性配置内部线程池。
  • URIEncoding: 用于指定URI的字符编码,tomcat8.x版本后默认是UTF-8。

1.5 Engine

Engine作为servlet引擎的顶级元素,内部可以嵌入:Cluster,Listener,Realm,Valve, Host等;如果在Engine 下配置了Realm,则此配置在当前Engine下的所有Host共享

  • name:用于指定Engine的名称,默认是Catalina,这个名称会影响一部分Tomcat的存储路径(如临时文件)
  • defaultHost: 默认使用的虚拟主机名称,当客户请求指向的主机无效时,将交由默认的虚拟主机处理,默认为localhost。

1.6 Host

Host元素用于配置一个虚拟主机。如果在Host下配置了Realm,则此配置在当前Host下的所有Context中共享

name: 当前Host通用的网络名,必须与DNS服务器上的注册信息一致,而且,必须要存在一个Host的name与Engine中defaultHost一致。

appBase:当前Host的应用基础目录,当前Host上部署的web应用均在该目录下,默认webapps

unpackWARs: 设置为true,Host在启动时会将appBase目录下的war包解压为目录,设置为false,Host则直接从war包启动

autoDepoly: 控制tomcat是否定期检测并自动部署新增或者变更的web应用。

1.7 Context

用于配置一个web应用,默认配置如下

2、tomcat部署项目的几个方式

1、直接将项目放到webapps的目录下即可

        将项目打成一个war包,在将war包放到webapps目录下即可

2、配置conf/server.xml文件

        <Host> 标签提中配置<Context>标签

        <Context doBase=“D:\hello” path=“/hehe”>  *doBase:项目存放的路径  *path:虚拟目录(网页usl访问的路径)

3、在tomcat\conf\Catalina\localhost下面创建任意名称的xml文件,在文件中编写<Context>标签

        <Context doBase=“D:\hello” path=“/hehe”>

Tomcat 集群搭建

1、Nginx的负载均衡策略有哪几种?

1、轮询(默认策略):交替

2、权重:在轮询的基础上,指定轮询的几率,适合服务器配置差异较大的情况

3、ip_hash:指定负载均衡按照基于客户端IP的分配方式,这个方法保证了相同的客户端的请求会发送到相同的服务器,以保证session会话。

 

2、为什么要session共享?

Tomcat集群中,如果用户需要登录,而这个时候,Tomcat做了负载均衡,用户登录的时候就会出现问题。

如下:第一次登录操作,访问的是Tomcat1,保存了session,第二次进行业务操作,但访问到了Tomcat2,此时Tomcat2是没有记录用户的session信息的,那么权限校验就无法通过。

3、session共享的三种方案

1、ip_hash策略

通过Nginx中负载均衡的ip_hash策略,对于一个用户发起的请求,经过ip_hash计算,只会转发到同一个Tomcat服务器上,这样就解决了session共享的问题。

2、session复制

顾名思义,就是用户访问到一个Tomcat时,这个Tomcat在记录session的同时,以广播的形式告知集群中的其他Tomcat,其他Tomcat复制这个session信息,那么下次如果访问转发到其他的Tomcat上时,因为已经赋值了session,因此可以正常访问。

配置方法:

        1、在sever.xml中,将如下注释放开

        

        2、 在web.xml中,添加<distributable/>标签

因为是广播复制,因此频繁的广播和复制会消耗性能,如果超过4个节点,则不推荐使用。

3、单点登录

single sign on(SSO),是目前比较流行的企业业务整合方案之一,sso的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统,也是用来解决集群环境session共享的方案之一。

简单来说,就是外部请求通过Nginx反向代理到一台Tomcat时,加一层认证服务,这个服务去redis中查询用户是否已经登录,首次登录将登录session存入到redis中,后续其他Tomcat服务器只要在redis中查到这个session信息,那么就可以认证通过。

4、Tomcat支持Https

1、生成密钥库文件

要实现https,就必须先具有tomcat证书。而JAVA中有自带的证书生成工具keytool,该命令执行完毕后,就会在本地生成一个密钥文件 tomcatkey.keystore

keytool -genkeypair -alias 'tomcat' -keyalg 'RSA' -keystore '/usr/local/tomcat/conf/tomcat.keystore

2、将密钥库文件放置在 tomcat/conf目录下

3、配置tomcat/conf/sever.xml文件

<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" maxThreads="150" schema="https" secure="true" SSLEnabled="true">
    <SSLHostConfig>
        <Certificate certificateKeystoreFile="证书位置" certificateKeystorePassword="密码"	type="RSA"/>
    </SSLHostConfig>
</Connector>

4、接着就可以使用8443端口访问https (免费的浏览器不信任,但是可以点击高级继续访问)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值