百日筑基第六十天-学习一下Tomcat

百日筑基第六十天-学习一下Tomcat

一、Tomcat 顶层架构

在这里插入图片描述

Tomcat 中最顶层的容器是 Server,代表着整个服务器,从上图中可以看出,一个 Server可以包含至少一个 Service,用于具体提供服务。Service 主要包含两个部分:Connector 和 Container。从上图中可以看出 Tomcat 的心脏就是这两个组件,他们的作用如下:
【1】Connector 用于处理连接相关的事情,并提供 Socket 与 Request 和 Response相关的转化;
【2】Container 用于封装和管理 Servlet,以及具体处理 Request请求;

一个 Tomcat 中只有一个 Server,一个 Server 可以包含多个 Service,一个 Service 只有一个 Container,但是可以有多个Connectors,这是因为一个服务可以有多个连接,如同时提供 Http 和 Https链接,也可以提供向相同协议不同端口的连接,示意图如下(Engine、Host、Context下边会说到):

在这里插入图片描述

多个 Connector 和一个 Container 就形成了一个 Service,有了 Service 就可以对外提供服务了,但是 Service 还要一个生存的环境,必须要有人能够给她生命、掌握其生死大权,那就非 Server 莫属了!所以整个 Tomcat 的生命周期由 Server 控制。另外,上述的包含关系或者说是父子关系,都可以在 tomcat 的 conf目录下的 server.xml 配置文件中看出。

二、简要解释下 server.xml 配置文件的信息

server.xml 是 Tomcat 中最重要的配置文件,server.xml 的每个元素都对应了 Tomcat中的一个组件;通过对xml文件中元素的配置,可以实现对 Tomcat 中各个组件的控制。

<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN"><Listener className="org.apache.catalina.startup.VersionLoggerListener"/><Listener SSLEngine="on" className="org.apache.catalina.core.AprLifecycleListener"/><Listener className="org.apache.catalina.core.JasperListener"/><Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener"/><Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"/><Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener"/><GlobalNamingResources><Resource auth="Container" description="User database that can be updated and saved"  factory="org.apache.catalina.users.MemoryUserDatabaseFactory" name="UserDatabase" pathname="conf/tomcat-users.xml" type="org.apache.catalina.UserDatabase"/></GlobalNamingResources><Service name="Catalina"><Connector port="8080" protocol="HTTP/1.1" connectionTimeOut="20000" redirectPort="8443"/><Connector port="8009" protocol="AJP/1.3" redirectPort="8443"/><Engine defaultHost="localhost" name="Catalina"><Realm className="org.apache.catalina.realm.LockOutRealm"><Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/></Realm><Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true"><Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" pattern="%h %l %u %t &quot;%r&quot; %s %b" prefix="localhost_access_log." suffix=".txt"/><Context docBase="cas-server-webapp" path="/cas" reloadable="true" source="org.eclipse.jst.j2ee.server:cas-server-webapp"/><Context docBase="portal" path="/portal" reloadable="true" source="org.eclipse.jst.jee.server:portal"/></Host></Engine></Service>
</Server>

server.xml 的整体架构(简洁版):

<Server><Service><Connector /><Connector /><Engine><Host><Context /><!-- 现在常常使用自动部署,不推荐配置Context元素,Context小节有详细说明 --></Host></Engine></Service>
</Server>

【1】顶层元素:<Server></Server><Server>元素是整个配置文件的根元素,<Server>元素代表一个 Engine元素以及一组与之相连的 Connector元素。 【2】连接器:<Connector><Connector> 代表了外部客户端发送请求到特定 Service的接口;同时也是外部客户端从特定Service 接收响应的接口。 【3】容器:<Engine>``<Host>``<Context>:容器的功能是处理 Connector接收进来的请求,并产生对应的响应。Engine 包含Host,Host 包含 Context。一个 Engine组件可以处理 Service中的所有请求,一个 Host组件可以处理发向一个特定虚拟主机的所有请求,一个 Context组件可以处理一个特定 Web应用的所有请求。

三、Tomcat 都有哪些核心组件

【1】Server:Server元素在最顶层,代表整个 Tomcat容器,因此他必须是 server.xml中唯一一个最外层的元素。一个 Server元素可以有一个或多个 Service元素。

<Server port="8005" shutdown="SHUTDOWN">
</Server>

可以看到,最外层有一个 <Server>元素,shutdown 属性表示关闭 Server的指令;port 属性表示 Server接收 shutdown指令的端口号,设置为-1可以禁掉该端口。Server 的主要任务,就是提供一个接口让客户端能够访问到这个 Service集合,同时维护它所包含的所有的 Service的生命周期,包含如何初始化,如何结束服务,如何找到客户端要访问的 Service。
【2】Service:在 Connector 和 Engine外面包一层,把它们组合在一起,对外提供服务。一个Service可以包含多个Connector,但是只能包含一个Engine;其中 Connector 的作用是从客户端接收请求,Engine 的作用是处理接收进来的请求。

<Server port="8005" shutdown="SHUTDOWN"><Service name="Catalina"></Service>
</Server>

如上图,Server 中包含一个名称为 “Catalina” 的Service。实际上,Tomcat 可以提供多个 Service,不同的 Service监听不同的端口。
【3】Connector:接收连接请求,创建 Request 和 Response对象用于和请求端交换数据;然后分配线程让 Engine来处理这个请求,并把产生的 Request 和 Response对象传给 Engine。通过配置 Connector,可以控制请求 Service的协议及端口号。

<Server port="8005" shutdown="SHUTDOWN"><Service name="Catalina"><Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /><Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /></Service>
</Server>

通过配置第一个 Connector,客户端可以通过 8080端口号协议访问 Tomcat。其中,protocol 属性规定了请求的协议,port 规定了请求的端口号,redirectPort 表示当强制要求 https而请求是 http时,重定向至端口号为 8443的Connector,connectionTimeout表示连接的超时时间。

在这个例子中,Tomcat 监听 Http请求,使用的是 8080端口,而不是正式的 80端口;实际上,在正式的生产环境中,Tomcat也常常监听8080端口。而不是80端口。这是因为在生产环境中,很少讲 Tomcat直接对外开放接收请求,而是在 Tomcat和客户端之间加一层代理服务器(如Nginx),用于请求的转发、负载均衡、处理静态文件等;通过代理服务器访问 Tomcat时,是在局域网中,因为一般仍使用8080端口。

第二个配置 Connector,客户端可以通过 8009端口使用 AJP协议访问 Tomcat。AJP协议负责和其他的Http服务器(如Apache)建立连接;在把 Tomcat与其他服务器集成时,就需要用到这个连接器,之所以使用 Tomcat和其他服务器集成,是因为 Tomcat可以用作 Servlet/JSP容器,但是对静态资源处理速度较慢,不如 Apache和 IIS等 HTTP服务器;因此常常将 Tomcat和 Apache等集成,前者做 Servlet容器,后者处理静态资源,而 AJP协议便负责 Tomcat与 Apache的连接。Tomcat 和 Apache等集成的原理如下图:

在这里插入图片描述

【4】Engine:Engine 组件在 Service 组件有且只有一个;Engine 是 Service组件中的请求处理组件。Engine组件从一个或多个Connector 中接收并处理,并将完成的响应返回给 Connector,最终传递给客户端。前面说到,Engine、Host 和 Context都是容器,但是它们不是平行关系,而是父子关系:Engine 包含 Host,Host 包含 Context。

<Server port="8005" shutdown="SHUTDOWN"><Service name="Catalina"><Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /><Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /><Engine name="Catalina" defaultHost="localhost"></Engine></Service>
</Server>

其中 name属性用于日志和错误信息,在整个 Server中应该是唯一的。defalutHost 属性指定了默认的 host名称,当发往本机的请求指定的 host名称不存在时,一律使用 defaultHost指定的 host进行处理;因此 defaulthost的值,必须与 Engine中的一个Host组件的 name属性值匹配。
【5】Engine 和 Host:Host 是 Engine的子容器。Engine 组件中可以内嵌1个或者多个 Host组件,每个 Host组件代表 Engine中的一个虚拟主机。Host组件至少有一个,且其中一个的 name必须与 Engine组件中的 defaultHost属性相匹配。
【6】Host 的作用:Host 虚拟主机的作用,是运行多个 Web应用(一个 Context 代表一个 Web应用),并负责安装、展开、启动、结束每个 Web应用。Host 组件代表的虚拟主机,对应服务器中一个网络名实体(如"www.test.com"或IP地址"116.25.25.25");为了使用户可以通过网络名连接Tomcat服务器,这个名字应该在DNS服务器上注册。

客户端通常使用主机名来标识它们希望连接的服务器,该主机名也会包含在 HTTP请求头中,Tomcat 从 HTTP头中提取出主机名,寻找名字匹配的主机。如果没有匹配,请求会发送至默认的主机。因此默认主机不需要再 DNS服务器中注册网络名,因为任何与所有 Host名称不匹配的请求,都会路由至默认主机。
【7】Host 的配置:name 属性指定虚拟主机的主机名,一个 Engine有且只有一个 Host组件的 name属性和 Engine组件的 defaultHost属性相匹配;一般情况下,主机名需要是在 DNS服务器中注册网络名,但是 Engine指定的 defaultHost不需要。

<Server port="8005" shutdown="SHUTDOWN"><Service name="Catalina"><Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /><Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /><Engine name="Catalina" defaultHost="localhost"><Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"></Host></Engine></Service>
</Server>

unpackWARs 指定了是否将代表 Web应用的 WAR文件解压;如果是 true,通过解压后的文件结构运行该 Web应用,如果是false,直接使用 WAR文件运行 Web应用。
【8】Context:Context元素代表在虚拟主机上运行的一个Web应用。在后文中,提到 Context、应用或 Web应用,他们都代指Web应用,每个 Web应用基于 WAR文件,或 WAR文件解压后对应的目录(这里称为应用目录)Context 是 Host 的子容器,每个 Host 都可以定义任意多的 Context元素。<Context>元素的配置:Context 元素最重要的属性是 docBase 和 path,此外reloadable 属性也比较常用。

docBase 指定了该 Web应用使用 war包路径,或应用目录。需要注意的是:在自动部署场景下(配置文件位于 xmlBase中),docBase 不在 appBase目录中,才需要指定;如果 docBase指定的 war包或应用目录就在 appBase中,则不需要指定。因为 Tomcat会自动扫描 appBase中的 war包和应用目录,制定了反而造成问题。

path 指定了访问该Web应用上下文路径,当请求到来时,Tomcat 根据 Web应用的 path属性与 URL匹配程度来选择 Web应用处理相应请求。例如:Web 应用 app1的 path属性是"/app1",Web应用 app2的path属性是"/app2",那么请求/app1/index.html会交由app1来处理;而请求 /app2/index.html会交由 app2来处理。如果一个 Context元素的 path属性为"",那么这个Context是虚拟主机的默认的 Web应用;当请求的uri与所有的 path都不匹配时,使用该默认Web应用来处理。

但是,需要注意的是,在自动部署场景(配置文件位于xmlBase中),不能指定path属性,path属性由配置的文件的文件名,WAR文件的文件名或应用目录的名称自动推导出来。如扫描 Web应该时,发现xmlBase目录下的app1.xml,或appBase目录下的 app1.WAR或 app1应用目录,则该Web用于的path属性是"app1"。如果名称不是app1而是ROOT,则该Web应用时虚拟主机默认的Web应用,此时path属性推导为""。

reloadable属性指示tomcat是否在运行时监控在 WEB-INF/classes和WEB-INF/lib目录下class文件的改动。如果值为 true,那么当 class文件改动时,会重新 web应用的重新加载。在开发环境下,reloadable 设置为 ture便于调试;但是在生产环境中设置为 true会给服务器带来性能压力,因此reloadable参数的默认值为false。在该例子中,docBase 位于 Host的 appBase目录之外;path属性没有指定,而是根据 app1.xml自动推导为 “app1”。

<Context docBase="D:\Program Files\app1.war" reloadable="true"></Context>

若是自动部署(即 autoDeploy=“true”),那么 server.xml配置文件中没有 Context元素的配置。这是因为 Tomcat开启了自动部署,Web应用没有在 server.xml中配置静态部署,而是由 Tomcat通过特定的规则自动部署。

四、Web 的自动部署

要开启 Web应用的自动部署,需要配置所在的虚拟主机;配置的方式就是在配置 Host元素的 deployOnStartup和 autoDeploy属性。如果 deployOnStartup 和 autoDeploy设置为 true,则 tomcat启动自动部署:当检测到新的 Web应用或 Web应用更新时,会触发应用的部署(或重新部署)。二者的主要区别在于

【1】deployeOnStartup 为 true时,Tomcat在 启动时检查Web应用,且检测到所有的Web应用都试做新应用; 【2】autoDeploy为 true时,Tomcat 在运行时定期检查新的 Web应用或 Web应用的更新;

通过配置 deployOnStartup 和 autoDeploy 可以开启虚拟主机自动部署Web应用;实际上,自动部署依赖于检查是否有新的或更改过的 Web应用,而 Host元素中的 appBase和 xml配置设置了检查 Web应用更新的目录。

其中,appBase 属性指定 Web应用所在的目录,默认值是 webapps,这是一个相对路径,代表 Tomcat根目录下的 webapps文件夹。xmlBase 属性指定 Web应用的 XML配置文件所在的目录,默认值为 conf/<engine_name><engine_name>,例如上面例子中,主机 localhost 的 xmlBase的默认值是 $TOMCAT_HOME/conf/Catalina/localhost。

五、appBase 和 docBase的区别

【1】appBase:这个目录下面的子目录将自动被部署为应用,且 war文件将被自动解压缩并部署为应用,默认为 tomcat下webapps目录。
【2】docBase:指定需要关联的项目自动解压并部署到 appBase目录下。项目的名称由 path属性决定。
先部署 <Context path="" docBase="/app/tomcat/webapps/xxx"> 需要注意,docBase 所在的文件或者 war包必须存在。否则项目启动找不到对应的目录。此时文件解压到 appBase目录下,根据 path属性,决定解压后的文件名。

若采用了 <Host name="localhost" appBase="webapp" autoDeploy="true"> 配置,那么 appBase目录下的应用目录将会再次部署。此时项目是部署了两遍。解决办法,设置 autoDeploy=“false”。

六、Tomcat 顶层架构小结

【1】Tomcat 中只有一个Server,一个 Server可以有多个 Service,一个 Service可以有多个 Connector和一个 Container;
【2】Server 掌管着整个 Tomcat的生死大权;
【3】Service 是对外提供服务的;
【4】Connector 用于接受请求并将请求封装成 Request 和 Response来具体处理;
【5】Container 用于封装和管理 Servlet,以及具体处理 Request请求;

知道了整个 Tomcat顶层的分层架构和各个组件之间的关系以及作用,对于绝大多数的开发人员来说 Server和 Service对我们来说确实很远,而我们开发中绝大部分进行配置的内容是属于Connector 和 Container的,所以接下来介绍一下 Connector 和Container。

七、Connector 和 Container的微妙关系

由上述内容我们大致可以知道一个请求发送到 Tomcat之后,首先经过 Service然后会交给我们的 Connector,Connector 用于接收请求并将接收的请求封装为 Request 和 Response来具体处理,Request 和 Response封装完之后再交由 Container进行处理,Container 处理完请求之后再返回给 Connector,最后在由 Connector通过 Socket将处理的结果返回给客户端,这样整个请求的就处理完了!

Connector 最底层使用的是 Socket来进行连接的,Request 和 Response是按照 HTTP协议来封装的,所以 Connector同时需要实现 TCP/IP协议和 HTTP协议。Tomcat 既然处理请求,那么肯定需要先接收到这个请求,接收请求这个东西我们首先就需要看一下 Connector。

八、Container 架构分析

Container 用于封装和管理 Servlet,以及具体处理 Request请求,在Connector内部包含了4个子容器,结构图如下:

在这里插入图片描述

4个子容器的作用分别是:
【1】Engine:引擎,用来管理多个站点,一个Service最多只能有一个Engine;
【2】Host:代表一个站点,也可以叫虚拟主机,通过配置Host就可以添加站点;
【3】Context:代表一个应用程序,对应着平时开发的一套程序,或者一个 WEB-INF目录以及下面的 web.xml文件;
【4】Wrapper:每一 Wrapper封装着一个 Servlet;

下面找一个 Tomcat的文件目录对照一下,如下图所示:

在这里插入图片描述

Context 和 Host 的区别是 Context 表示一个应用,我们的 Tomcat 中默认的配置下 webapps下的每一个文件夹目录都是一个Context,其中 ROOT目录中存放着主应用,其他目录存放着子应用,而整个 webapps就是一个 Host站点。我们访问应用Context 的时候,如果是 ROOT 下的则直接使用域名就可以访问,例如:www.ledouit.com,如果是 Host(webapps)下的其他应用,则可以使用 www.ledouit.com/docs 进行访问,当然默认指定的根应用(ROOT)是可以进行设定的,只不过 Host站点下默认的主营用是 ROOT目录下的。

看到这里我们知道 Container是什么,但是还是不知道 Container是如何进行处理的以及处理完之后是如何将处理完的结果返回给Connector的。

九、Container 如何处理请求的

Container 处理请求是使用 Pipeline-Valve 管道来处理的!(Valve是阀门之意)Pipeline-Valve 是责任链模式,责任链模式是指在一个请求处理的过程中有很多处理者依次对请求进行处理,每个处理者负责做自己相应的处理,处理完之后将处理后的请求返回,再让下一个处理着继续处理。

在这里插入图片描述

但是!Pipeline-Valve 使用的责任链模式和普通的责任链模式有些不同!区别主要有以下两点:
【1】每个 Pipeline 都有特定的 Valve,而且是在管道的最后一个执行,这个 Valve叫做 BaseValve,BaseValve是不可删除的;
【2】在上层容器的管道的 BaseValve中会调用下层容器的管道;

我们知道 Container包含四个子容器,而这四个子容器对应的 BaseValve分别在:StandardEngineValve、StandardHostValve、StandardContextValve、StandardWrapperValve。Pipeline的处理流程图如下:

在这里插入图片描述

【1】Connector 在接收到请求后会首先调用最顶层容器的Pipeline来处理,这里的最顶层容器的 Pipeline就是EnginePipeline(Engine的管道);
【2】在 Engine的管道中依次会执行 EngineValve1、EngineValve2 等等,最后会执行 StandardEngineValve,在StandardEngineValve 中会调用 Host管道,然后再依次执行 Host 的 HostValve1、HostValve2 等,最后在执行StandardHostValve,然后再依次调用 Context的管道和 Wrapper的管道,最后执行到 StandardWrapperValve;
【3】当执行到 StandardWrapperValve 的时候,会在 StandardWrapperValve中创建 FilterChain,并调用其 doFilter方法来处理请求,这个 FilterChain包含着我们配置的与请求相匹配的 Filter和Servlet,其 doFilter方法会依次调用所有的 Filter的 doFilter方法和 Servlet的 service方法,这样请求就得到了处理!
【4】当所有的 Pipeline-Valve都执行完之后,并且处理完了具体的请求,这个时候就可以将返回的结果交给 Connector了,Connector 在通过 Socket的方式将结果返回给客户端。

十、tomcat 容器是如何创建 servlet类实例?用到了什么原理?

当容器启动时,会读取在 webapps目录下所有的 web应用中的 web.xml文件,然后对 xml文件进行解析,并读取 servlet注册信息。然后,将每个应用中注册的 servlet类都进行加载,并通过反射的方式实例化。(有时候也是在第一次请求时实例化)在servlet 注册时加上如果为正数,则在一开始就实例化,如果不写或为负数,则第一次请求实例化。

十一、共享 session处理

目前的处理方式有如下几种:
【1】使用 Tomcat本身的 Session复制功能。参考http://ajita.iteye.com/blog/1715312(Session复制的配置)方案的有点是配置简单,缺点是当集群数量较多时,Session 复制的时间会比较长,影响响应的效率;
【2】使用第三方来存放共享Session:目前用的较多的是使用 memcached来管理共享Session,借助于memcached-sesson-manager来进行Tomcat的Session管理。参考http://ajita.iteye.com/blog/1716320(使用MSM管理Tomcat集群session)
【3】使用黏性 session的策略:对于会话要求不太强(不涉及到计费,失败了允许重新请求下等)的场合,同一个用户的session 可以由 nginx或者 apache交给同一个 Tomcat来处理,这就是所谓的 session sticky策略,目前应用也比较多。参考:http://ajita.iteye.com/blog/1848665(tomcat session sticky)Nginx 默认不包含 session sticky模块,需要重新编译才行(windows下我也不知道怎么重新编译)优点是处理效率高多了,缺点是强会话要求的场合不合适。

十二、关于 Tomcat 的 session数目

这个可以直接从 Tomcat的 web管理界面去查看即可,或者借助于第三方工具 Lambda Probe 来查看,它相对于 Tomcat自带的管理稍微多了点功能,但也不多 ;

十三、Tomcat 一个请求的完整过程

首先 DNS 解析机器,一般是 ng服务器 ip地址,然后 ng 根据 server的配置,寻找路径为 yy/的机器列表,ip和端口。最后 选择其中一台机器进行访问。下面为详细过程:
【1】请求被发送到本机端口8080,被在那里侦听的Coyote HTTP/1.1 Connector获得;
【2】Connector把该请求交给它所在的Service的Engine来处理,并等待来自Engine的回应;
【3】Engine 获得请求localhost/yy/index.jsp,匹配它所拥有的所有虚拟主机Host;
【4】Engine 匹配到名为 localhost 的 Host(即使匹配不到也把请求交给该 Host处理,因为该Host被定义为该 Engine的默认主机);
【5】localhost Host 获得请求 /yy/index.jsp,匹配它所拥有的所有 Context;
【6】Host 匹配到路径为 /yy的 Context(如果匹配不到就把该请求交给路径名为”“的Context去处理);
【7】path=”/yy” 的 Context获得请求 /index.jsp,在它的 mapping table中寻找对应的 servlet;
【8】Context 匹配到 URL PATTERN为 *.jsp的 servlet,对应于JspServlet类;
【9】构造 HttpServletRequest 对象和 HttpServletResponse对象,作为参数调用 JspServlet的doGet或 doPost方法;
【10】Context 把执行完了之后的 HttpServletResponse对象返回给 Host;
【11】Host把HttpServletResponse对象返回给 Engine;
【12】Engine 把 HttpServletResponse对象返回给 Connector;
【13】Connector 把 HttpServletResponse对象返回给客户 browser;

十四、Tomcat 工作模式

Tomcat是一个 JSP/Servlet容器。其作为 Servlet容器,有三种工作模式:独立的 Servlet容器、进程内的 Servlet容器和进程外的Servlet容器。进入 Tomcat 的请求可以根据 Tomcat 的工作模式分为如下两类:
【1】Tomcat 作为应用程序服务器:请求来自于前端的web服务器,这可能是 Apache, IIS, Nginx等;
【2】Tomcat 作为独立服务器:请求来自于web浏览器;

Tomcat 的工作一般分为三种:
【1】bio:传统的Java I/O操作,同步且阻塞I/O,一个线程处理一个请求,并发量高时,线程数较多,浪费资源;(已经很少有人在使用)
【2】nio:JDK1.4开始支持,同步阻塞或同步非阻塞IO,可以通过少量的线程来处理大量的请求;(从Tomcat 8版本开始默认就是这种模式)
【3】apr:以JNI的形式调用Apache HTTP服务器的核心动态链接库来处理文件读取或网络传输操作,从而大大地提高Tomcat对静态文件的处理性能;(企业中使用较多)

十五、如何对 Tomcat 进行优化

【1】关闭 Manager管理页面;(默认已经关闭)
【2】关闭 host-mangent管理页面;(默认已经关闭)
【3】对 Tomcat 日志进行分割;
【4】定义 Tomcat 404 错误返回的页面;
【5】对 JVM进行优化;
【6】对 Tomcat线程池进行优化;
【7】更改 Tomcat的工作的模式;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/407846.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI周报(8.18-8.24)

AI应用-XGO-Rider: 全球首款轮腿式桌面 AI 机器人 中国的 Luwu 智能打造的XGO-Rider 是全球首款轮腿式桌面 AI 机器人。这个小巧紧凑的机器人将轮式机器人的灵活性与腿式机器人的障碍处理能力相结合&#xff0c;可以全方位移动&#xff0c;轻松适应各种地形。 XGO-Rider 主要设…

服务商模式实现JSAPI小程序微信支付(javaphp)

官方文档 https://pay.weixin.qq.com/wiki/doc/apiv3_partner/open/pay/chapter2_1.shtml 使用wechatpay-php实现JSAPI支付&#xff08;服务商和普通商户&#xff09;文章浏览阅读1.3k次&#xff0c;点赞3次&#xff0c;收藏7次。之前我使用的sdk是“wechatpay-guzzle-middle…

python实用教程(二):安装配置Pycharm及使用(Win10)

上一篇&#xff1a;python实用教程&#xff08;一&#xff09;&#xff1a;安装配置anaconda&#xff08;Win10&#xff09;-CSDN博客 1、简介及下载 PyCharm是一款功能强大的 Python 编辑器&#xff0c;具有跨平台性。是Jetbrains家族中的一个明星产品。 下载地址&#xff…

redis实战——go-redis的使用与redis基础数据类型的使用场景(二)

一.go-redis操作hash 常用命令&#xff1a; redisClient.HSet("map", "name", "jack") // 批量设置 redisClient.HMSet("map", map[string]interface{}{"a": "b", "c": "d", "e"…

计算机毕业设计选题推荐-游戏比赛网上售票系统-Java/Python项目实战

✨作者主页&#xff1a;IT研究室✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

棚子影院CMS程序PHP源码

01, 棚子影视是我现在最常用的一个看视频的网站&#xff0c;支持观看电影、国漫&#xff01;动漫&#xff0c;电视剧、综艺、记录片、香港剧等等。同时棚子影视支持手机&#xff0c;PC端在线观看&#xff0c;不用下载任何播放器&#xff0c;直接电脑或者手机打开网址就可以在线…

vue3 RouterLink路由跳转后RouterView组件未加载,页面未显示,且控制台无任何报错

在使用 vue3 开发项目过程中&#xff0c;组件之间使用 router-link 跳转&#xff0c;但是当我开发的组件跳转到其他组件时&#xff0c;其他组件的页面未加载&#xff0c;再跳转回自己的组件时&#xff0c;自己的组件也加载不出来了&#xff0c;浏览器刷新后页面可以加载出来。但…

结合 curl 与住宅代理实现高效数据抓取

引言 什么是 curl&#xff1f;有哪些功能&#xff1f; 基本 curl 命令有哪些&#xff1f; 为什么要使用 curl 处理 HTTP 请求&#xff1f; 如何使用 curl 和住宅代理进行网络抓取&#xff1f; 总结 引言 在当今数据驱动的商业环境中&#xff0c;数据的获取和分析能力是企…

Redis | 非关系型数据库Redis的初步认识

本节内容相对理论&#xff0c;着重看基础通用命令这一节 Redis 非关 kv型{字典} 概念应用ubuntu安装配置 windows添加密码 可能问题【ubuntu】远程连接 基础通用命令 ⭐ 概念 特点&#xff1a; 1、开源的&#xff0c;使用C编写&#xff0c;基于内存且支持持久化 2、没有表 支持…

Linux服务器不能使用su切换到其他用户

1. 现象 使用非root用户登录系统后&#xff0c;想使用su - 切换到root时&#xff0c;输入正确的密码后出现&#xff1a; 一开始以为自己密码记错了&#xff0c;或者是系统被入侵后篡改了root用户密码&#xff0c;服务器上的数据非常重要。后面不通过SSH连接&#xff0c;直接去…

图文详解ThreadLocal:原理、结构与内存泄漏解析

目录 一.什么是ThreadLocal 二.ThreadLocal的内部结构 三.ThreadLocal带来的内存泄露问题 ▐ key强引用 ▐ key弱引用 总结 一.什么是ThreadLocal 在Java中&#xff0c;ThreadLocal 类提供了一种方式&#xff0c;使得每个线程可以独立地持有自己的变量副本&#xff0c;而…

AI副业:别只顾刷黑神话悟空!AI做神话账号,商单月入过万(附教程)

前言 国产3A大作《黑神话&#xff1a;悟空》一经发布&#xff0c;瞬间登顶steam榜首&#xff0c;打破单机游戏在线记录&#xff0c;全球几十万国外玩家听着中文配音&#xff0c;看着翻译过来的英文字幕&#xff0c;玩的不亦乐乎&#xff01; 甚至国外论坛上兴起了一股西游风&a…

[已解决]mac远程连接windows桌面:parallels client连接遇到的问题

[已解决]mac远程连接windows桌面&#xff1a;parallels client连接遇到的问题 问题一&#xff1a;网络不通问题二&#xff1a;远程windows防火墙导致无法连接问题三&#xff1a;远程桌面服务未启动问题四&#xff1a;家庭版&#xff08;非专业版&#xff09;windows导致的无法使…

快排补充(挖坑法,lomuto前后指针,非递归法)

挖坑法 挖坑法动态示意图 挖坑法方法分析 创建左右指针。⾸先从右向左找出⽐基准⼩的数据&#xff0c;找到后⽴即放⼊左边坑中&#xff0c;当前位置变为新 的"坑"&#xff0c;然后从左向右找出⽐基准⼤的数据&#xff0c;找到后⽴即放⼊右边坑中&#xff0c;当前位置…

P2P 文件共享:现代网络中的高效文件传输

在互联网的世界中&#xff0c;不同应用程序的数据传输方法各异。P2P文件共享&#xff08;Peer-to-Peer File Sharing&#xff09; 作为一种高效的文件传输方式&#xff0c;使得用户可以在没有中央服务器的情况下直接进行文件交换。本文将详细介绍P2P文件共享的基本原理、优势及…

vue3实现系统tab标签页面切换

功能&#xff1a; 支持刷新当前、关闭其他、关闭全部、关闭当前支持打开多个相同path不同路由参数的页面&#xff0c;将fullPath作为路由页面唯一值 UI组件&#xff1a; 使用的是element-plus中的el-tab组件&#xff0c;结构目录如下 代码实现&#xff1a; 下面是 TagsView…

缺失ffmpeg.dll要用什么修复方法?快速恢复丢失的ffmpeg.dll文件

多媒体软件用户常常会遭遇一个提示&#xff1a;系统无法找到ffmpeg.dll文件。这类情况经常在启动视频编辑软件、流媒体播放应用或其他音视频处理工具时出现&#xff0c;导致相关程序无法正确加载和执行。ffmpeg.dll是一种关键的动态链接库文件&#xff0c;负责处理复杂的视频和…

【实战教程】一键升级CentOS 7.9.2009至OpenSSL 1.0.2u:加固你的Linux服务器安全防线!

文章目录 【实战教程】一键升级CentOS 7.9.2009至OpenSSL 1.0.2u&#xff1a;加固你的Linux服务器安全防线&#xff01;一、 背景二、 升级步骤2.1 检查 OpenSSL 版本2.2 安装 OpenSSL 依赖包2.3 下载 OpenSSL 的新版本2.4 解压缩下载的文件2.5 编译并安装 OpenSSL2.5.1 切换到…

linux系统编程:网络通信

1.网络 1.粘包 tcp特点 面向连接 字节流&#xff08;TCP 将数据视为连续的字节流&#xff0c;没有明确的消息边界。会发生粘包问题。 避免粘包 特殊分隔符&#xff1a;在消息间加入特殊的分隔符&#xff08;如换行符或其他特殊字符&#xff09;&#xff0c;接收方根据分…

大模型时代的AI应用开发,可以不用,但必须会

成熟的“格子衫”和年轻的“脸庞”&#xff0c;与开发者有关的大会总是少不了这两种元素&#xff0c;Create 2024百度AI开发者大会也不例外。 过去几十年&#xff0c;层出不穷的编程语言、框架等新技术&#xff0c;把一代又一代年轻的脸庞&#xff0c;塑造为成熟的格子衫&…