1.引入
1.1Tomcat 应用在哪里,作用是什么
- tomcat 应用于 web 开发中,面向客户端和服务端充当中间者角色,相当于一个有着平台兼容性的收(请求)发(资源)器;
1.2.Tomcat 服务器与容器属性
1.2.1 容器与服务器的联系与区别
- 容器与服务器的关系
- 容器是位于应用程序/组件和服务器平台之间的接口集合,使得应用程序/组件可以方便部署到服务器上运行;
- 服务器
- 服务器的一般概念:服务器是提高计算服务的设备,应具备承担和保障服务的能力;
- 应用服务器与 web 服务器
- 应用服务器:通过各种协议把业务逻辑暴露给客户端,提供应用程序所实现的服务;
- web 服务器:向浏览器等 web 客户端提供文档浏览、数据文件下载等服务;
容器
Tomcat 是Java Servlet,JavaServer Pages,Java Expression Language 和 Java WebSocket(Java EE)技术的开源实现,具有多重属性
- web 服务器:通过 HTTP 提供 HTML 页面等静态内容的请求访问;
- servlet 容器:实现了servlet 规范,可以运行 Servlet 程序;
- 应用服务器:可通过 servlet 容器,调用 servlet 处理动态请求;
- tomcat 与其它服务器的关系
- tomcat servlet 与其它容器的关系
- Tomcat 与其它服务器的组合
- Nginx + Tomcat
- 先是通过 Nginx 反向代理服务器接收请求,匹配分离动态/静态请求(动静分离),如果是静态请求,则转发到另外的 Nginx WEB 服务器上,返回静态内容;如果是动态请求,则转发到后面的 Tomcat 应用服务器,处理动态请求的业务逻辑;
- Nginx + Tomcat
1.3 Tomcat 工具使用
1.3.1 基础配置
- 安装及配置 详见
- 下载:http://tomcat.apache.org/
- 安装/卸载:解压压缩包; 删除目录;
- 启动
- bin/startup.bat,双击运行该文件;
- 访问:浏览器输入: http://xxxx:8080;
- (正常)关闭:bin/shutdown.bat 或者 Ctrl+C;
- 配置
- 部署项目的方式
- 直接将项目(打包成 war 包)放到 webapps 目录下,war 包会自动解压缩;
- [不安全]配置 conf/server.xml 文件:在 host 标签中
- docBase:项目存放的路径; path:虚拟目录;
- 在 conf\Catalina\localhost 创建任意名称的 xml 文件,并编写
; - 注意:此时对应的虚拟目录为 xml 文件的名称;
- 部署项目的方式
Java 动态项目目录结构
-
2.Tomcat 静态架构
2.1文件目录结构
bin:该目录下存放的是二进制可执行文件,安装版会有两个exe文件,解压版会有 startup.bat 和shutdown.bat 文件,startup.bat 用来启动 Tomcat,但需先配置 JAVA_HOME 环境变量;
- conf
- server.xml:配置整个服务器信息,如修改端口号,添加虚拟主机等;
- tomcatusers.xml:存储 tomcat 用户的文件,保存着 tomcat 的用户名、密码及角色信息;
- web.xml:部署描述符文件,该文件中注册了很多 MIME 类型,客户端浏览器通过 MIME类型处理响应结果,如显示 html(mime=text/html) 或弹出下载窗口(mime=exe);
- context.xml:对所有应用的统一配置,通常不去配置;
- lib:Tomcat的类库,里面是一大堆 jar 文件,建议只把 Tomcat 需要的 Jar 包放到这个目录下;
- logs:日志文件,记录 Tomcat 启动和关闭的信息,启动异常也会记录在日志文件中;
- temp:存放 Tomcat 的临时文件,可在停止 Tomcat 后删除;
- webapps:存放 web 项目,每个文件夹对应一个应用项目;
- 静态网站:1)在 webapps下创建一个 xx 目录;2)在 webapps\xx\下创建 index.html;
- 动态网站:1)在 webapps下创建一个 xx 目录;2)在 webapps\xx\下创建 WEB-INF 目录;3)在 webapps\xx\WEB-INF\ 下创建 web.xml;4)在webapps\hello1\下创建 index.html;
- 注意
- 动态网站相比静态网站,在项目名目录下多了一个 WEB-INF 子文件,其里边存放着当前项目的 web.xml;
- webapps 存放的是内部应用,若要调用 webapps 以外的外部应用,需在 tomcat 中配置: conf/server.xml 或 conf/catalana/localhost/i
tcast_hello.xml 的 path、docBase;
- work:webapps 中的项目每次运行都会生成的文件;
- LICENSE:许可证;
-
2.2 两个重要的配置文件
2.2.1 server.xml
server.xml 的每一个元素都对应于 tomcat 中的一个组件,主要用于对各个组件和端口进行配置;
- 结构图
实例
<?xml version='1.0' encoding='utf-8'?>
<!--Server:最顶层,代表整个Tomcat容器 , port:指定负责监听的关闭端口 主要用于tomcat服务关闭时回调给应用程序的监听 -->
<Server port="8005" shutdown="SHUTDOWN">
<!-- Listener:监听器 可以在特定事件发生时执行特定的操作;被监听的事件通常是Tomcat的启动和停止-->
<!-- VersionLoggerListener:当Tomcat启动时,该监听器记录Tomcat、Java和操作系统的信息。该监听器必须是配置的第一个监听器 -->
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<!-- JasperListener:在Web应用启动之前初始化Jasper,Jasper是JSP引擎,把JVM不认识的JSP文件解析成java文件,
然后编译成class文件供JVM使用。 -->
<Listener className="org.apache.catalina.core.JasperListener" />
<!-- JreMemoryLeakPreventionListener:类加载器导致的内存泄露有关 -->
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<!-- GlobalResourcesLifecycleListener:初始化< GlobalNamingResources>标签中定义的全局JNDI资源;
如果没有该监听器,任何全局资源都不能使用 -->
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<!-- ThreadLocalLeakPreventionListener:当Web应用因thread-local导致的内存泄露而要停止时,该监听器会触发线程池中线程的更新。当线程执行完任务被收回线程池时,
活跃线程会一个一个的更新。只有当Web应用(即Context元素)的renewThreadsWhenStoppingContext属性设置为true时,该监听器才有效。 -->
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
<!-- 服务器的全局JNDI资源 -->
<GlobalNamingResources>
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
</GlobalNamingResources>
<!-- service:服务组件,对外提供服务,一个service代表一个服务 -->
<Service name="Catalina">
<!--Connector: 接收连接请求,创建Request和Response对象用于和请求端交换数据;
然后分配线程让Engine来处理这个请求,并把产生的Request和Response对象传给Engine。
可以配置多个Connector, 通过创建不同的Connector指定不同的port和协议访问Tomcat服务
常见的属性有:
protocol:协议,有HTTP、AJP等各种协议等
connectionTimeout:链接超时时间
redirectPort:指定服务器正在处理http请求时,收到了一个SSL传输请求后,重定向的端口号
-->
<Connector
keepAliveTimeout="10000"
namePrefix="catalina-exec-"
maxThreads="1024"
minSpareThreads="4"
maxIdleTime="6000"
connectionTimeout="1000"
compression="on"
compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain"
enableLookups="false"
maxKeepAliveRequests="1"
maxConnections="1024"
acceptCount="2000"
port="8008"
protocol="org.apache.coyote.http11.Http11NioProtocol"
redirectPort="8444"
/>
<!--Engine:请求处理组件,在service组件中有且只有一个,Service组件中的请求处理组件。
Engine组件从一个或多个Connector中接收请求并处理,并将完成的响应返回给Connector,最终传递给客户端
他有以下属性:
name:Engine的逻辑名称,在日志和错误消息中会用到
defaultHost:指定默认主机,如果没有分配哪个Host来执行用户请求,由这个值所指定的主机来处理,
这个值必须和<Host>元素中的其中一个的name值相同
-->
<Engine name="Catalina" defaultHost="localhost">
<!--
Host:可以有一或多个Host组件,每个Host组件代表Engine中的一个虚拟主机。
Host的作用是可以运行多个Web应用(一个Context代表一个Web应用),并负责安装、展开、启动和结束每个Web应用,
它的属性有:
name:指定虚拟主机的主机名,一般情况下,主机名需要是在DNS服务器中注册的网络名,但是Engine指定的defaultHost不需要
unpackWARs:是否将代表Web应用的WAR文件解压;如果为true,通过解压后的文件结构运行该Web应用,如果为false,直接使用WAR文件运行Web应用
appBase:应用程序基本目录,即存放应用程序的目录,可以是计算机中的绝对目录,也可以是相对CATALINA_HOME的相对目录,不填则默认为tomcat下webapps目录
alias:指定主机别名
autoDeploy:是否自动发布;用于检测appBase下的文件,如果有新增或者修改,为true则会自动重新启动项目
-->
<Host
name="localhost"
appBase=""
unpackWARs="true"
autoDeploy="false">
<!--
Context:指当前Host上运行的一个Web应用 ,每个Host中可以定义任意多的Context元素。
它有以下属性:
path:访问该Web应用的上下文路径
docBase:指定了该Web应用使用的WAR包路径,或应用目录。
reloadable:tomcat是否在运行时监控在WEB-INF/classes和WEB-INF/lib目录下class文件的改动
-->
<Context
path=""
docBase="/Users/jaybril-pro/Documents/workspace/neno/BlackEye-SCAN/web"
reloadable="true" />
</Host>
</Engine>
</Service>
</Server>
- 属性:shutdown-关闭 server; port-server接收 shutdown 指令的端口号(-1表示端口禁用);
- 功能:1)提供访问到 service 集合的端口;2)维护所包含 service 的生命周期;
:一个 server 可有多个 service,将 connector 和 Engine 包在一起以对外提供服务; :一个 service 可有多个 connector - 属性:port-请求端口,protocol-请求协议,redirectPort-当协议不一致时重定向端口,connectionTimeout-连接超时时间,minProcessors/maxProcessors-服务器启动时创建的处理请求的最少/最多线程数,enableLookups- 为 true 表示调用 request.getRemoteHost()进行 DNS 查询来得到远程客户端的实际主机名否则返回其 ip 地址,acceptCount-处理队列中允许放的请求数(超过这个数的请求将不予处理);
- 功能:1)表明客户端可通过 xx 端口使用 xx 协议访问 tomcat;2)接收连接请求,创建 Request 和 Response 对象;3)分配线程让 Engine 处理请求,且把生成的 Request 和 Response 对象传给 Engine;
:一个service 只有一个 Engine - 属性:name-server 唯一,defaultHost-找不到指定 host 时使用默认 host(要求 defaultHost 的值必须与 Engine 中的一个 Host 组件【默认主机】的 name 值匹配);
- 功能:从一个或多个 connector 中接收请求并处理,并将完成的响应返回给 connector;
: 一个 Engine 可有多个 Host - 属性:name-主机名(对应注册在 DNS 上的网络名),unpackWARs-是否将代表 Web 应用的WAR 文件解压,appBase-存放应用程序的目录;
- 功能:运行多个 Web 应用,并负责安装、展开、启动和结束每个 Web 应用;
:一个 host 可有多个 context - 启动一个 web 项目时 web.xml 加载顺序
- web 容器从配置文件 web.xml 读取
和 两个结点; - 容器创建一个ServletContext(servlet上下文),被 web 项目的所有部分共享;
- 容器将
转换为键值对,并交给 servletContext; - 容器创建
中的类实例,创建监听器;
- web 容器从配置文件 web.xml 读取
- conf/web.xml 和 WEB-INF/web.xml 的关系
- tomcat 部署应用程序时,先读取通用的 conf/web.xml,然后再读取 web应用程序中的 WEB-INF/web.xml;
- conf/web.xml 中的设定会应用于所有 web 应用程序,而某些 web 应用程序的 WEB-INF/web.xml 中的设定只应用于该应用程序本身;
- 所有 JavaWeb 项目中 web.xml 都继承自服务器下的 web.xml;
WEB-INF/web.xml 的功能
第一阶段:JVM 相关资源
(1) $JAVA_HOME/jre/lib/ext/.jar
(2) 系统 classpath 环境变量中的.jar和*.class
- 第二阶段:Tomcat 自身相关资源
(1) $CATALINA_HOME/common/classes/.class
(2) $CATALINA_HOME/commons/endorsed/.jar
(3) $CATALINA_HOME/commons/i18n/.jar
(4) $CATALINA_HOME/common/lib/.jar
(5) $CATALINA_HOME/server/classes/.class
(6) $CATALINA_HOME/server/lib/.jar
(7) $CATALINA_BASE/shared/classes/.class
(8)$CATALINA_BASE/shared/lib/.jar
- 第三阶段:Web 应用相关资源
(1) 具体应用的 webapp 目录: /WEB-INF/classes/.class
(2) 具体应用的 webapp: /WEB-INF/lib/.jar
2.4 Tomcat 重要组件
2.4.1 各组件之间的关系图
- 补充:service 容器中除了 connector 和 Engine 外,还包括 session、loging 等组件;
注意:Executor 的线程池大小是为 Engine 组件设置,而不是为 Connector 设置的,Connector 的线程数量由Connector 组件的 acceptorThreadCount 属性来设置,若在配置文件中设置该组件,则必须设置在 Connector组件的前面,以便在 Connector 组件中使用 executor 属性来引用配置好的 Executor 组件。
2.4.2 连接器 connector
connector 是 tomcat 的主干,其运行效率在一定程度上影响了 tomcat 的整体性能;
- connector 主要功能:1)接收连接请求;2)创建 request 和 response 对象用于和请求端交换数据;3)分配线程给 engine 处理请求,并把 request 和 response 对象传递给 engine 引擎;4)将 engine 处理后的 response 返回给客户端;
- 连接与请求的关系
- 连接是 TCP 层面的(传输层),对应 socket;
- 请求是 HTTP 层面的(应用层),必须依赖于 TCP 的连接实现;
- 一个 TCP 连接中可能传输多个 HTTP 请求;
- 两类 connector :HTTPConnector 和 AJPConnector;
- Connector 包含的组件
- Protocol:协议的抽象,对不同的通信协议进行封装,如 HTTP 协议和 AJP 协议;
- Endpoint:用于处理底层 Socket 的网络连接
- 接收端的抽象,由于使用了不同的 I/O 模式,因此存在很多类型的 Endpoint,如 BIO 模式的JionPoint、NIO 模式的 NioEndPoint 和本地库 I/O 模式的 APREndpoint;
- Acceptor:接收客户端连接的接收器组件;
- Executor:处理客户端请求的线程池,既能使用 Service 的共享线程池,也可使用私有线程池;
- Processor:将 Endpoint 接收到的 Socket 封装成 Request
- 组件是处理客户端请求的处理器,不同的协议和不同的 I/O 模式都有不同的处理方式,所以存在不同类型的 Processor;
- Mapper:路由器,提供了对客户端请求 URL 的映射功能,即可以通过它将请求转发到对应的 Host 组件、Context 组件、Wrapper 组件以进行处理并响应客户端;
- CoyoteAdapter:将封装好的 Request 交给 Container 进行具体处理
- 适配器,负责将 Connector 组件和 Engine 容器适配连接起来,把接收到的客户端请求报文解析生成的请求对象 Request 和响应对象 Response 传递到 Engine 容器来处理;
- 组件之间的关系图
- 注:不同的协议、不同的通信方式,ProtocolHandler 会有不同的实现;
- 源码解析
- container 的三种运行模式:BIO、NIO、APR
2.4.3 容器 container
- container 的三种运行模式:BIO、NIO、APR
- 四个子容器的关系图及作用
- Engine :引擎,用来管理多个站点, 一个 Service 最多只能有一个Engine;
- Host :代表一个站点,也可以叫虚拟主机,通过配置 Host 就可以添加站点;
- Context :代表一个应用程序,对应平时开发的一套程序或一个 WEB-INF 目录以及下面的 web.xml 文件;
- Wrapper :每个 Wrapper 封装着一个servlet;
- 一个 Host 里可有不同 Context,对应不同 contextPath,默认 Context 的 contextPath 为空格(“”) 或 斜杠(/);
-
2.4.4 Listener 详见
监听器是一个实现特定接口的普通 java 程序,专门用于监听另一个 java 对象的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法立即被执行;
- 设计到的设计模式:监听者模式
- JavaWeb 中的监听器是 Servlet 规范中定义的一种特殊类,它用于监听 web 应用程序中的 ServletContext, HttpSession 和 ServletRequest 等域对象的创建与销毁事件,以及监听这些域对象中的属性发生修改的事件。
- JavaWeb 三大域对象:内置 map 集合 和 Attribute 的 get/set,实现数据共享
- 生命周期是对象从创建到销毁;
- ServletRequest
- 作用域:只在当前请求有效,每一次请求都是一个新的 request 对象,如果在 web 组件之间需要共享同一个请求中的数据,只能使用请求转发;
- HttpSession
- 作用域:只在一次会话中有效,每一次会话都是一个新的 session 对象,如果一次会话中的多个请求之间需要共享数据,只能使用 session;
- ServletContext(application)
- 作用域:tomcat 从启动到关闭表示一个应用,在一个应用中只有一个 application 对象,作用于整个 web 应用,可以实现多次会话之间的数据共享;
- 作用域共享数据的方式:setAttribute getAttribute removeAttribute
- 注:在哪一个作用域中设置共享数据,只能从该作用域中取数据;
- 在选择域对象的时候,能用范围小的绝不用范围大的;
- 四组监听器
- 第一组:用于监听 Servlet 三个域对象的创建与销毁
- ServletRequestListner
- HttpSessionListener
- ServletContextListener
- 创建:服务器启动针对每一个 web 应用创建 ServletContext;【contextInitialized】
- 销毁:服务器关闭前先关闭代表每一个 web 应用的 ServletContext;【contextDestroyed】
- 第二组:用于监听 Servlet 三个域对象的属性变化(设置、删除、修改)
- ServletRequestAttributeListener
- HttpSessionAttributeListener
- ServletContextAttributeListener
- 第三组:用于通知被绑定到 Session 对象的属性
- HttpSessionBindingListener
- 第四组:用于监听 Session 的钝化与活化
- HttpSessionActivationListener
- 第一组:用于监听 Servlet 三个域对象的创建与销毁
- 多个监听器的执行顺序:按照监听器在 web.xml 中注册顺序执行;
自定义监听器 案例
用于 Web 容器对请求和响应做统一处理,例如统一改变 HTTP 请求内容和响应内容,可以作用在某个 Servlet 或一组 Servlet;
- 本质:JSP、Filter 都是 Servlet 的进化版,JSP 负责视图展示,Filter 负责过滤;
- 作用:拦截请求与响应;
- 应用场景:权限控制、敏感词汇过滤、压缩加密响应信息等;
- 作用在请求资源执行之前,进行权限检查,检查用户是否有权限,
- 作用在请求资源执行之前,对 Request 和 Response 对象进行预处理,从而实现一些 web 应用的全局性设置,比如解决中文乱码问题;
- 作用在最终响应输出之前,对输出 Response 对象中的数据进行处理,例如将输出的数据进行压缩;
- 作用(以 httpServlet 为例)
- 从 HTTP 协议中获取信息(这是因为 filterchain.doFilter 传入的参数为解析的 request 和 response)
- 获取请求头部,如 getHeader、getHeaders;
- 获取 cookie,如 getCookies;
- 获取 session,如 getSession,session ;
- 获取请求路径,如;getContextPath、getServletPath;
- 之所以能够获取 contextPath,是因为 filter 被部署在 servletContext 中;
- 能够获取 servletPath 是因为 filter 在部署的时候需标明作用的 servlet 的路径;
- 从 HTTP 协议中获取信息(这是因为 filterchain.doFilter 传入的参数为解析的 request 和 response)
- web.xml 配置以及在分发机制中的使用
- 初始化时机
- Filter 其实是加了 load-on-startup 的 servlet,即 Tomcat 启动时 Filter 就已经加载创建并完成初始化,所以一个应用每种过滤器只有一个;
- 多个 Filter 拦截顺序问题(过滤链)
- chain.doFilter(req, resp); //如果没有调用,则拦截
- 注意区分 filter.dofilter 方法和 filter.dofilter 方法
- 执行顺序取决于
在 web.xml 中的位置,越靠前越优先; - 涉及到的设计模式:责任链模式
- chain.doFilter(req, resp); //如果没有调用,则拦截
- FilterConfig 对象的作用:1)获取 FilterConfig 名称; 2)获取 FilterConfig 初始化参数; 3)获取ServletContext 对象;
- Filter 映射规则配置:1)精确匹配,以‘/’开头; 2)匹配所有 /;扩展名匹配 .jsp;
- 单独拦截某个 Servlet
- 方法一:配置
的 值 = 的 值; - 方法二:配置
的 值;
- 方法一:配置
- Filter+动态代理解决全站编码问题
- 创建一个 Filter 类,实现 Filter 接口,并重写接口方法;
- web.xml 配置 Filter
// 注册 <filter> // 对应 filterConfig 对象 <description>:用于描述标签,非必须 <init-param>:为过滤器的初始化提供参数,非必须 <filter-name>userFilter</filter-name> <filter-class>com.tuobida.filter.UserFilter</filter-class>//指定该过滤器使用的web工程中的哪一个filter类,包含包名与类名 </filter> // 映射 <filter-mapping> <filter-name>userFilter</filter-name>//必须同<filter>标签下的<filter-name>的值一致 <url-pattern>/*</url-pattern>//设置过滤器要拦截过滤的请求路径 <servlet-name>如果只要拦截过滤访问某个Servlet,就可以使用该标签来替代<url-pattern> <dispatcher>设置拦截过滤客户端请求的方式,有REQUEST,INCLUDE,FORWARD,ERROR四种(请注意均为大写), ,非必须则默认为REQUEST,使用多个<dispatcher>标签来设置多种请求方式; </filter-mapping>
- web.xml 配置 Filter
2.4.6 Servlet
2.4.6.1 背景
- Servlet 是 JavaEE 规范的一种,主要是为了扩展 Java 作为 Web 服务的功能,统一接口,由其他内部厂商(tomcat、jetty 等)内部实现 web 的功能;
- Servlet、Listenner 和 Filter 都是由 Tomcat 在解析 web.xml 时通过反射创建的;
- Servlet 是单实例,其中的 service() 方法是多线程的;
- servlet 工作模式
- 关于 serclet 的基本类图和调用关系
2.4.6.2 Servlet 传入的三个参数
- ServletConfig
Request 和 Response
在 web.xml 中对 servlet 进行配置
利用注解进行配置: 在 servlet 类的上面写入注解 @WebServlet(“/hello”);
2.4.6.4 如何实现一个 Servlet
HttpServlet,继承关系 HttpServlet -> GenericServlet -> Servlet,主要实现了 Service 功能,在继承 HttpServlet 自定义 Servlet 时,不能修改 service,而应重写 doGet() 、doPost() 等;
- 涉及到的设计模式:模板模式
2.4.6.5 Servlet 映射规则
- 分配结果
- 对于静态资源,Tomcat 最后会交由一个叫做 DefaultServlet 的类来处理;
- 对于 Servlet ,Tomcat 最后会交由一个叫做 InvokerServlet 的类来处理;
- 对于JSP,Tomcat 最后会交由一个叫做 JspServlet 的类来处理;
- web.xml 映射规范
- 以 ‘/‘ 字符开始、以 ‘/*’ 后缀结尾的字符串使用路径匹配;
- 以 ‘*.’ 为前缀的字符串使用扩展名匹配;
- 空字符串(””)是一个特殊的 URL 模式,其精确映射到应用的上下文根,即 http://host:port// 请求形式,在这种情况下,路径信息是 ‘/‘ 且 servlet 路径和上下文路径是空字符串(””);
- 只包含 ‘/‘ 的字符串表示应用的默认 Servlet,在这种情况下,servlet 路径是请求 URL 减去上下文路径且路径信息是 null;
- 使用 URL 路径匹配 web 应用程序的顺序
- 精确匹配,查找一个与请求路径完全匹配的 Servlet;
- 前缀路径匹配,递归的尝试匹配最长路径前缀的 Servlet,通过使用 “/“ 作为路径分隔符,在路径树上一次一个目录的匹配,选择路径最长的;
- 扩展名匹配,如果 URL 最后一部分包含扩展名,如 .jsp,则尝试匹配处理此扩展名请求的 Servlet;
- 如果前三个规则没有匹配成功,那么容器要为请求提供一个默认 Servlet;
- 注意:
- 只使用第一个匹配的 Servlet,后续不再尝试;
- 容器在匹配时区分大小写;
- 实现请求映射的一般方法:首先构建一个路由表,然后按照规范进行匹配,最后返回匹配结果;
- Mapper:存储请求路由表并执行匹配;
- MapperListener:负责监听所有的 Host、Context、Wrapper 构建路由表;
- MappingData:请求映射结果;
-
2.4.6.6 发生在 Servlet 之间的转发与重定向
转发和重定向都能让浏览器获得另外一个 URL 所指向的资源,但两者的内部运行机制区别较大;
- 转发
- 案例:request.getRequestDispatcher (“demo.jsp”). forward(request, response);//转发到demo.jsp
- 获得转发对象(RequestDispatcher) 的两种方式:
- 通过 HttpServletRequest 的 getRequestDispatcher() 方法;
- 通过 ServletContext 的 getRequestDispatcher() 方法;
- 补充:这说明 Dispatcher 也在 ServletContext 容器中,且在分配请求给 Servlet 的时候,Servlet 会保留对该 Dispatcher 的引用;
- 特点:转发是由 tomcat 内部完成的,不会影响客户端的请求操作,客户端也无法获得转发过程;
- 重定向
- 案例:response.sendRedirect(“demo.jsp”); //重定向到demo.jsp
- 特点:由 response 将重定向的地址发给客户端,客户端会对返回的新地址再次发出请求并等待响应;
转发(forword())和重定向(sendRedirect())的主要区别
- 跨域性
- sendRedirect() 方法可作用于同一主机的不同 web 应用程序甚至其他服务器,而 forward() 方法只能将请求转发给同一 web 应用的组件;
- 跳转 jsp
- sendRedirect() 方法不能转发到“/WEB-INF/”路径下的 jsp 页面资源,而 forword() 可以,如 request.getRequestDispatcher(“/WEB-INF/jsp/login.jsp”).forward(request, response);
- 客户端操作
- 跨域性
Realm 是 Tomcat 中为 web 应用程序提供访问认证和角色管理的机制,若配置了 Realm,则不需要在程序中写web 应用登陆验证代码以及管理用户角色,甚至不需要手写登陆界面 ;
-
3.Tomcat 动态运行
3.1 运行一次请求的过程
用户在浏览器输出网站:http://www.xxx.com/customer/index.html;
- 浏览器解析出域名 www.xxx.com 并且去请求 DNS 服务器,通过 DNS 获取相应的域名对应的 IP 地址和端口,例如(123.1.1.1:8099);
- 通过 IP 地址找到 IP 对应的服务器后,要求建立 TCP 连接;
- 通讯双方连接之后,请求被发送到服务器端口 8099;
- 根据请求的协议,将请求传给 server.xml 中端口号 port 为 8099 的 Connectort;
- 该 Connector 把请求分配到对应 service 下的 Engine 组件,由 Engine 处理请求,Cinnector 等待响应;
- Engine 收到请求之后,根据请求路径匹配到相应的 host,并将请求交给 host 处理;
- host 匹配相对路径 /customer/index.html,找到相应的 context;
- 匹配到相应 context 后,根据路径访问相应的 servlet;【这部分需要通过 web.xml 的 context 结点吗?】
- 根据请求构造 HttpServletRequest 和 HttpServletResponse 对象,并调用 Servlet 的 doGet 或 doPost 方法;
- servlet 中处理逻辑之后,把 HttpServletResponse 对象返回给 Host;
- host 把 HttpServletResponse 逐级传递到 Engine、Connector;
- Connector 把响应结果返回到客户端的浏览器,同时告知浏览器展示的文件格式是什么;
-
3.2 相关传输协议
3.2.1 http/https
浏览器请求时的请求头信息
GET / HTTP/1.1 Host: www.ramki.com Proxy-Connection: keep-alive User-Agent: Mozilla/5.0 (Windows NT 6.2) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11 Accept: text/html,application/xhtml+xml,application/xml;q=0.9 Accept-Encoding: gzip,deflate,sdch Accept-Language: en-US,en;q=0.8
背景知识
- http 和 https 使用的连接方式不同,连接端口不同,前者是 80,后者是 443;
- http 请求格式与响应格式
- TCP/IP、http、Socket 的关系
- TPC/IP 是传输层协议,主要解决数据如何在网络中传输,而 HTTP 是应用层协议,主要解决如何包装数据;
- Socket 是应用层与 TCP/IP 协议族通信的中间软件抽象层,是一组接口,封装了复杂的 TCP/IP 协议;
- 延伸 - WebSocket
- 产生背景 - http 用于及时通讯的局限
- 通过轮询在特定的时间间隔,由浏览器向服务器发送 Request 请求,然后将最新数据返回给浏览器;
- 产生过多不必要请求,浪费流量和服务器资源,每一次请求应答,都浪费一定流量在相同头部信息上;
- WebSocket 与 HTTP 的关系
- 同:1)建立在 TCP 之上,可靠传输; 2)应用层协议
- 异:1)HTTP 是单向通信(浏览器->服务端);2)WebSocket 全双工通信,且需通过握手建立连接;
- 联系:WebSocket 握手连接通过 HTTP 请求完成,再单独建立一条 TCP 的通信通道进行数据传输;
- WebSocket 与 Socket 的关系
AJP 是 Apache 与其他服务器之间的通信协议,通常在集群环境中,例如前端 web 服务器和后端应用服务器或servlet 容器,使用 AJP 会比 HTTP 有更好的性能;
3.3 Tomcat 运行原理
3.3.1 Tomcat 的启动过程
tomcat 假如有 main 函数,其处理流程应该为:
- 请求处理流程线
- 启动流程的时序图
-
3.3.2 connector 的并发处理
Connector 处理请求的流程
- 在 accept 队列中接收连接(当客户端向服务器发送请求时,如果客户端与 OS 完成三次握手建立了连接,则 OS 将该连接放入 accept 队列);
- 在连接中获取请求的数据,生成 request 和 response;
- 调用 servlet 容器处理请求,返回 response;
- JIoEndpoint(BIO 实现的 Connector)
- Acceptor 接收 socket 后,从 Worker 线程池中找出空闲的线程处理 socket,如果 worker 线程池没有空闲线程,则 Acceptor 将阻塞;
- Worker 为 Tomcat 自带的线程池,可通过
配置其他线程池;
- Worker 为 Tomcat 自带的线程池,可通过
- Acceptor 接收 socket 后,从 Worker 线程池中找出空闲的线程处理 socket,如果 worker 线程池没有空闲线程,则 Acceptor 将阻塞;
Xml代码
- <Executor name=”tomcatThreadPool” namePrefix=”catalina-exec-“
- maxThreads=”150” minSpareThreads=”4”/>
- NIoEndpoint(NIO 实现的 Connector)
- Acceptor 接收 socket 后,通过队列将请求发送给 Poller,当 Poller 从队列中取出 socket 后,先注册到Selector 中,然后通过遍历 Selector,找出其中可读的 socket,再使用 Worker 中的线程处理相应请求;
- 读取 socket 并交给 Worker 中的线程,为非阻塞模式;
- Acceptor 接收 socket,以及使用 worker 线程处理请求,均为阻塞方式;
- Acceptor 接收 socket 后,通过队列将请求发送给 Poller,当 Poller 从队列中取出 socket 后,先注册到Selector 中,然后通过遍历 Selector,找出其中可读的 socket,再使用 Worker 中的线程处理相应请求;
- 并发处理过程的源码图示
3.3.3 lifeCircle 和 valueBase
3.3.3.1 lifeCircle
org.apache.catalina.Lifecycle 是一个接口,org.apache.catalina.util.LifecycleBase 实现了 Lifecycle 接口,而 Server / Service / Engine / Host / Context / Wrapper 等组件都继承了 LifecycleBase,也就是说这些组件在发生生命周期事件的时候都可以被监听器监控
在tomcat中容器相关的好多组建都实现了Lifecycle接口,当tomcat启动时,其依赖的下层组件会全部进行初始化。 并且可以对每个组件生命周期中的事件添加监听器。
3.3.3.2 valueBase
3.3.4 Tomcat 的类加载机制
https://developer.aliyun.com/ask/62429?spm=a2c6h.13159736
https://www.jianshu.com/p/51b2c50c58eb
加载类和资源的顺序为:
1、/Web-INF/classes
2、/Web-INF/lib/.jar
3、Bootstrap
4、System
5、$CATALINA_HOME/common/classes
6、$CATALINA_HOME/common/endores/.jar
7、$CATALINA_HOME/common/lib/.jar
8、$CATALINA_HOME/shared/classes
9、$CATALINA_HOME/shared/lib/.jar
- tomcat 实际是运行在 jvm 中的一个进程,是 java 项目与 jvm 的中间容器;
- web 项目没有入口方法( main 方法),意味着 web 项目中的方法不会自动运行起来,之所以把 web 项目部署进tomcat 的 webapp 中,目的是让 tomcat 去调用已有方法来为客户端返回需要的资源和数据;
由于 tomcat 只有在项目被部署进 webapp 下后才确定有什么方法,所以通过 java 反射来实现类的动态加载、实例化、方法获取及调用等;
4.问题与思考
问题
- spring 中的 tomcat 在哪 ? servletcontext 和 applicationcontext 的关系?
- web 项目开发:tomcat + python 与 tomcat + java 的区别?
- 有关请求路径的匹配在 tomcat 中有两次,都是拿同一个 ip 匹配的吗
- 猜想一:如果是的话,那说明一个服务端对应的是一个集群,有很多的 ip,两次拿都是拿同一个 ip,在集群这个 ip 表中做匹配;
猜想二:多个域名可对应一个 ip 地址,则第一次匹配是 dns 解析的 ip 地址,第二次匹配是域名;
<Host name="www.ramki.com" appbase="ramki_webapps" /> <Host name="www.krishnan.com" appbase="krishnan_webapps" /> <Host name="www.blog.ramki.com" appbase="blog_webapps" />
- 接受请求和发送响应的 connector 是同一个吗? 猜测应该不是。。
- HttpServlet 为什么为一个抽象类
- 明确了请求协议 http,也就确定这个协议下有几种请求方式,但是 servlet 又是面向应用的,所以在处理不同的请求方式时,逻辑应该不同,所以 httpServlet 用 service 做一个间接的抽象体来判断和转发请求,把那些具体的请求处理逻辑留给子类实现;
- 总结
- tomcat 的多个容器存在嵌套关系,容器的主要功能有三:一是存放和配置组件,二是管理组件的生命周期,三是与其它容器通信;
- 凡是 Tomcat 中涉及的容器,都会有 init 和 destroy 方法;
- Tomcat 中三个主要组件所用到的设计模式
- Servlet-模板模式,LIstener-监听者模式,FilterChain-职责链模式;
参考
tomcat服务器的Server.xml配置详解
web服务器、tomcat、servlet是什么?它们之间的关系又是什么?
各种容器与服务器的区别与联系:Servlet容器 WEB容器 Java EE容器 应用服务器 WEB服务器 Java EE服务器
tomcat
tomcat中server.xml配置详解
tomcat web.xml 详解
web.xml 加载过程
Tomcat运行web程序过程及server.xml配置
tomcat 启动流程及管理
网址(url),域名,ip地址,dns,hosts之间的关系
tomcat 运行过程和简单模拟
tomcat 腾讯云+社区
Tomcat内核详解(六):Connector组件
构分析(connector BIO 实现)
深入理解Tomcat(十)Connector
深入理解 tomcat(八)container
Java Web之Servlet的三大作用域对象
javaweb 四大域对象
27、监听器学习
listener
Servlet、Listener、Filter、JSP
Servlet的学习之Filter过滤器技术(1)
http 协议格式详解
tomcat 多线程模型浅析
tomcat高并发下优化详解及连接数和线程池
tomcat 并发处理请求
tomcat 的路由请求实现的 mapper
servlet/tomcat等容器/springMVC之间的关系
Java匹马行天下之JavaWeb核心技术——Servlet
- Servlet-模板模式,LIstener-监听者模式,FilterChain-职责链模式;