概述
本博客只是博主对tomcat基础知识的回归和总结,即只记录了tomcat的基本工作流程和配置,后续可能会推出tomcat参数调优等相关博客,尽请期待!
环境配置
- redhat7
- jdk 1.8.0_212
- tomcat-7.0.105
tomcat环境变量
由于tomcat是用java写的,所以tomcat的运行需要依赖JAVA_HOME环境变量,一般在安装jdk的时候,我们都会设置JAVA_HOME ,所以一般无需再为tomcat配置环境变量。但是如果你想在一台机器上部署多个tomcat实例的话,我们就需要设置CATALINA_HOME这个环境变量,指向tomcat的安装目录,这样子这台机器就知道访问的是那个tomcat实例了。
目录结构
- bin:可执行文件
- conf:配置文件
- lib:tomcat的依赖库
- logs:日志
- temp:临时文件夹
- webapps:默认的应用部署目录
- work:供web应用使用
启动方式
- *nix平台
- $CATALINA_HOME/bin/startup.sh
- $CATALINA_HOME/bin/catalina.sh start
- windows平台
- $CATALINA_HOME\bin\startup.bat
- $CATALINA_HOME\bin\catalina.bat start
停止方式
- *nix平台
- $CATALINA_HOME/bin/shutdown.sh
- $CATALINA_HOME/bin/catalina.sh stop
- windows平台
- $CATALINA_HOME\bin\shutdown.bat
- $CATALINA_HOME\bin\catalina.bat stop
案例
启动tomcat
在完成环境配置后,我们首先来启动一下tomcat,由于博主使用的系统是redhat7,所以采用$CATALINA_HOME/bin/startup.sh的方式来执行。
可以看到tomcat已经启动成功了。
打开控制台页面
一般来说,启动之后,只要在浏览器输入127.0.0.1:8080就可以直接返回tomcat页面,但由于博主是在一台远程的linux机器上运行的,而且8080端口号已经被占用了,所以我们可以修改端口号,开放端口,重启tomcat就可以运行了。这里我修改之后的地址是http://192.168.142.10:8099/,直接打开,看到如下页面,说明tomcat启动成功。
创建简单web应用并部署到tomcat
我们在tomcat的安装目录下,创建一个简单的饭馆应用,只卖豆浆和面条。其中豆浆用来模拟静态资源,面条用来模拟动态资源。项目源码请点击这里下载。
接着定位到web应用所在的目录下,对NoodlesServlet.java文件进行编译。
javac -cp $CATALINA_HOME/lib/servlet-api.jar WEB-INF/classes/com/netease/NoodlesServlet.java
如果没有报错且在同级目录下生成了class文件,说明编译成功了。 接着我们将restaurant项目移动到tomcat安装目录下的webapps目录下,这就完成了web应用的部署。
mv restaurant/ webapps/
现在我们来试着访问一下静态资源,在这里就是豆浆的页面,在浏览器上输入网址:http://192.168.142.10:8099/restaurant/SoybeanMilk.html , 出现Soybean Milk的字样,说明成功访问到了。 接着我们来尝试访问动态资源,对应这里就是访问面条的页面。在浏览器上输入网址:http://192.168.142.10:8099/restaurant/noodles ,这里的面条没有添加任何配料,配料返回的是默认的Tomcat。
接着我们为面条添加西红柿,http://192.168.142.10:8099/restaurant/noodles?vegetable=tomato ,返回如下页面,页面刷新了,说明访问动态资源成功了。
拓展
配置JVM的启动参数
我们知道,在生产环境上,有时需要对tomcat进行参数调优,使得tomcat的运行状态满足我们实际的需要。其中,配置JVM参数就是其中的一种调优方式。这种配置很简单。比如我们需要在项目启动时,添加这样的JVM参数“-server -Xms2048m -Xmx2048m”,我们只需要定义JAVA_OPTS即可。以redhat7为例,为了使配置永久生效,我们需要编辑 /etc/profile 这个文件,在文件的最后一行写上
export JAVA_OPTS="-server -Xms2048m -Xmx2048m"
保存文件后,通过
source /etc/profile
配置就能够生效了,这时候tomcat重启,就能够读取到最新的JVM参数了。
server.xml配置
server.xml位于conf目录下,是tomcat的核心配置文件。它的结构大致如下:
<Server>
<Service>
<Connector>
</Connector>
<Engine>
<Host>
<Context></Context>
</Host>
</Engine>
</Service>
</Server>
他们的关系大致如下:
- Sever 是整个xml文件的根元素,可以认为,一个Server元素代表一个tomcat,下属多个Service。
- Service 从这一层往下,我们一般称为容器(Container),Catalina是它的具体实现,这也就说明了为什么前面配置环境变量,用的就是Catalina的这个名字。下属多个Connector,下属一个Engine。
- Connector 用于接收用户请求。Coyote是Connector的组件,实现了很多种不同的Connector,其中最常见的是BIO Connector,使用了传统的阻塞式IO,当客户端有连接过来时,服务端就会分配一个线程去处理。如果请求没有得到响应,对应的线程就会一直等待,直到超时。
- Engine 处理Connector接收到的请求,下属多个Host。
- Host 虚拟主机,决定路由到的主机,默认是localhost,表示本机;下属多个Context。
- Context 实际上就对应着一个web应用。
请求处理流程
Connector参数配置
- port 端口号。
- address 一个服务器可能有多个ip,如果不配置这个参数,则默认在所有ip上监听请求,有时候因为安全考虑,这是不被允许的,所以需要用address指定监听的ip。
- protocol 通讯协议。一般都用HTTP/1.1。性能调优时,可以更换为其他协议。
- connectionTimeout 客户端连接超时时间,单位为毫秒。
- acceptCount 等待队列最大长度,默认值为100。超过限制后,超出部分的请求将不会被处理。
- maxConnections 支持的最大连接数。配置为-1之后,表示不限制最大连接数。tomcat会使用默认的线程池,如果想对线程池参数进行进一步的修改。可以去除Executor元素的注释,直接修改对应的参数。
线程池配置
<Executor name="myThreadPool" namePrefix="catalina-exec-"
maxThreads="1" minSpareThreads="1"/>
<!-- A "Connector" represents an endpoint by which requests are received
and responses are returned. Documentation at :
Java HTTP Connector: /docs/config/http.html (blocking & non-blocking)
Java AJP Connector: /docs/config/ajp.html
APR (HTTP/AJP) Connector: /docs/apr.html
Define a non-SSL HTTP/1.1 Connector on port 8080
-->
<Connector port="8099" protocol="HTTP/1.1"
connectionTimeout="200000"
executor="myThreadPool"
redirectPort="8443" />
在这里,我们去除Executor元素的注释,定义了一个名称为myThreadPool的线程池,它的最大线程数最小空闲线程数都为1。并修改Connector元素,引用这个线程池。这里要特别说明一下,如果在Connector中已经配置了连接池,那么当Connector中配置的acceptCount、maxConnections等属性在线程池中存在时,将会被覆盖,以线程池中的配置为准。接下来我们重启tomcat,来看看效果。 直接在服务器内部,通过curl命令发起请求:
这里立即返回了响应。为了演示同一时刻只能有一个线程存在,我们改用telnet命令的方式,手动开启连接。
telnet localhost 8099
开启连接后,输入如下语句,在语句的末尾,如果连续按下两次回车,就能得到响应结果,我们暂时只按一次,让这个连接一直保持开启的状态。
GET /restaurant/noodles HTTP/1.1
Host: localhost:8099
Connection: keep-alive
这时候我们开启另外一个窗口,也输入同样的命令,如果连续按下两次回车,发现没有响应结果,接着我们在第一个窗口按下回车键,可以发现立刻返回了响应。第一个窗口返回了响应之后,第二个接口也立马返回了相同的响应。这就说明我们实现了同一时刻只有一个线程的配置。
Tomcat日志配置
- 作用
- 获悉运行情况
- 调试
- 分类
- 系统运行日志
- 访问日志
- 应用日志
日志配置的修改还是在server.xml文件中,下面我们来演示如何配置用户访问日志。
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<!-- SingleSignOn valve, share authentication between web applications
Documentation at: /docs/config/valve.html -->
<!--
<Valve className="org.apache.catalina.authenticator.SingleSignOn" />
-->
<!-- 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 "%r" %s %b" />
</Host>
日志的配置信息主要在Host标签下的Value标签中。如上图,这是原始的日志格式。他主要有以下几个节点:
- className 容器访问请求的日志处理类。
- directory 日志所在的目录。
- prefix 日志文件名的前缀。
- suffix 日志文件名的后缀。
- fileDateFormat 日志的时间戳格式。
- rotatable 是否日志切割,true表示进行日志切割,根据fileDateFormat定义的时间戳格式进行切割。
- pattern 日志的格式。这里定义了很多种通配符,具体可以查看tomcat的文档。
在这里我们自定义需要的日志配置,如下:
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<!-- SingleSignOn valve, share authentication between web applications
Documentation at: /docs/config/valve.html -->
<!--
<Valve className="org.apache.catalina.authenticator.SingleSignOn" />
-->
<!-- 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="my_access_log." suffix=".log"
fileDateFormat="yyyy-MM-dd.HH.mm"
rotatable="true"
pattern="method: %m, client ip: %a, time: %t "%r" statusCode: %s, byteSent: %b,User-Agent: %{User-Agent}i" />
</Host>
然后我们重启tomcat.继续使用curl发起请求。
然后我们来到tomcat的logs目录下,可以看到日志文件已经按照我们规定的格式生成了。
Tomcat部署
- 手动部署 将项目手动拷贝到webapps目录下
- war包部署 通过jar命令打包war包,将war包拷贝到webapps目录下
关于war包部署方式,举个例子,比如这里定位到我当前的restaurant项目目录下。通过
jar cvf restaurant.war .
这样的命令就可以打包成一个war包了。其中restaurant.war就是你想要生成的war包名,. 表示当前路径。然后将这个war包拷贝到webapps目录下即可。