在座各位老铁程序开发多年,想必Tomcat一直是都是你们的必用猫吧,在项目中配一下Tomcat,copy一份server.xml覆盖进来,就可以轻松愉快的把项目跑起来了。
但是…..
你们有没有想过Tomcat是怎么运行你们充满bug的程序的呢?server.xml里的这些垃圾配置又是什么用的呢?
下面,我附上一份花费多日呕心沥血制作而成的server.xml配置详解,费大家脑壳和钛合金眼睛仔细看看:
<?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>
通过研究上面的配置和注释,想必大家已经对这个配置的讲解理解的一塌糊涂了吧?因为密密麻麻花里胡哨的代码和汉字混杂在一起,看起来就像脑壳撞墙冒星星一样难受。
好吧,我们根据真实场景分析一下从用户在浏览器输入网址发请求到最终返回结果展示到网站这一个过程在客户端浏览器、提供web程序的服务器、Tomcat、web程序分别在哪个步骤做了什么骚操作:
1、 用户在浏览器输出网站:http://www.xxx.com/customer/index.html
2、浏览器解析出域名www.xxx.com并且去请求DNS服务器,通过DNS获取相应的域名对应的IP和端口如(123.1.1.1:8099)
3、通过IP地址找到IP对应的服务器后,要求建立TCP连接
4、通讯双方连接之后,请求被发送到服务器端口8099
5、该端口是Tomcat中的server.xml的Connector配置port,所以此时请求被相应的Connector接收到
6、Connector把请求分配到它里边的Engine组件,由它来处理,并且等待其响应
7、Engine收到请求之后,根据请求路径匹配到相应的host,交给host处理
8、host匹配相对路径/customer/index.html,找到相应的context
9、匹配到相应context后,根据路径访问相应的servlet
10、根据请求构造HttpServletRequest对象和HttpServletResponse对象,并调用Servlet的doGet或doPost方法
11、servlet中处理逻辑之后,把HttpServletResponse对象返回给Host
12、host把HttpServletResponse逐级传递到Engine、Connector
13、最终把响应结果返回到客户端的浏览器
14、浏览器把结果渲染呈现
至此,一个完整的http请求完成。结合这个流程再看上面的server.xml配置,应该是一点即通了吧。
觉得本文对你有帮助?请分享给更多人
关注「编程无界」,提升装逼技能