Tomcat权威指南
Tomcat开幕式
指定用户
useradd -g 46 -s /sbin/nologin -d /opt/tomcat/temp tomcat
-
-g
:用户组。 -
-s
:禁用shell并锁定用户名密码。 -
-d
:home目录。
启动与停止
启动与停止:
bin/catalina.sh run # 启动 bin/catalina.sh start # 启动,但输出重定向到文件 bin/startup # 同上一条 bin/catalina.sh stop # 停止 bin/shutdown.sh # 停止
startup
与catalina.sh run
会把输入重定向到文件:
$TOMCAT_HOME/logs/catalina.out
catalina脚本启动参数
-config <server.xml file> |
指定server.xml 配置文件
|
-nonaming | 禁用JNDI |
debug | 调试模式 |
embedded | 在嵌入模式中测试,开发时常用 |
jpda start | JPDA调试器方式启动 |
设置启动参数到全局Java环境变量:
export JAVA_OPTS="-Xmx256M"
其他重要参数:
CATALINA_HOME | 静态程序部分 |
CATALINA_BASE | 动态的网站与配置部分,包含:conf、logs、temp、webapps、work |
CATALINA_OPTS | 传递给Java的参数 |
CATALINA_TMPDIR | 临时文件的目录 |
重启
要重启时判断什么时候真正被关掉是一个麻烦。shutdown.sh
以后要查看进程是不是还在。
方法一:java带的命令:
jps | grep Bootstrap
方法二:系统工具;
ps auwwx | grep catalina.startup.Bootstrap
常见错误
端口占用
Linux:
netstat -a -tcp
-
-a
:显示激活状态的连接。 -
-tcp
:TCP连接。
BSD:
netstat -a -f inet
-
-f inet
:只显示 Internet[IPV4]连接。
配置Tomcat
指定独立网站目录
生成一专门的tomcat用户与用户组:
sudo groupadd tomcat sudo useradd tomcat -g tomcat -d /home/tomcat -s /bin/bash sudo mkdir /home/tomcat sudo chgrp -R tomcat /home/tomcat sudo chown -R tomcat /home/tomcat
生成目录放所有的网站,下面各个网站再那家独立的目录:
cd /home/tomcat mkdir tomcat-instance cd tomcat-instance mkdir groovywigs.com
网站目录下复制tomcat程序里的config
目录,还有其他目录。
例,不带管理工具的版本:
cp -a $CATALINA_HOME/conf . mkdir webapps logs temp work
例,带管理工具的版本:
cp -a $CATALINA_HOME/conf . cp -a $CATALINA_HOME/webapps . mkdir logs temp work
编辑conf/server.xml
,设置端口与目录位置:
- Shutdown port:此端口用于关闭Tomcat。当执行shutdown.sh脚本时,它会给此端口 发出一个信号,Tomcat的进程会监听此端口,如果接收到这样的信号,进程会清理退出 。
- Connector port:此端口是应用对外公开发布的端口。
- AJP port:Web服务器(例如Apache的httpd Server)通过此端口和Tomcat进行通信, 也可以使用它设置一个负载均衡服务器。
- Redirect port:如果此Connector支持非SSL请求和接收SSL请求,Catalina会自动 将请求指向到此端口。
<!-- server port --> <Server port="8105" shutdown="SHUTDOWN"> <Service name="Catalina"> <!-- connector port --> <Connector port="8180" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> <!-- redirect Port --> <!-- ajp port --> <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> <!-- redirect Port --> </Service> </Server>
建立启动脚本bin/startup.sh
:
#!/bin/sh export CATALINA_HOME=/opt/morganstudio/server/tomcat8 export CATALINA_BASE=/home/tomcat/tomcat-instance/groovywigs.com $CATALINA_HOME/bin/catalina.sh run
建立停止脚本bin/shutdown.sh
:
#!/bin/sh export CATALINA_HOME=/opt/morganstudio/server/tomcat8 export CATALINA_BASE=/home/tomcat/tomcat-instance/groovywigs.com $CATALINA_HOME/bin/catalina.sh stop
Java VM配置
-Xms384M | |
-Xmx384M | |
-Djava.security.debug=all | 为安全输出所有调试信息 |
-Djava.awt.headless=true | 允许在没有图形显示安装软件情况下运行 |
-Duser.language=en | |
-Dfile.encoding=UTF-8 | |
-Djava.net.preferIPv4Stack=true | 使用IPv4而不是IPv6,有些BSD系统上一定要开 |
-enableassertions | 启用assertion检查 |
-verbose:class | |
-verbose:gc |
打开远程调试:
JAVA_OPTS="-Xdebug \ -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n"
通过JMX实现本地管理与监控:
CATALINA_OPTS = " - Dcom.sun.management.jmxremote=true \ - Dcom.sun.management.jmxremote.ssl = false \ - Dcom.sun.management.jmxremote.authenticate = false"
如果要通过远程管理与监控:
CATALINA_OPTS = " - Dcom.sun.management.jmxremote.port = 8008 \ - Dcom.sun.management.jmxremote.ssl = false \ - Dcom.sun.management.jmxremote.authenticate = false \ - Dcom.sun.management.jmxremote.password.file=/path/to/pw/file"
防止因为服务器没有图形界面而出错:
-Djava.awt.headless=true
指定语言环境信息,可以直接在shell中完成:
$ LANG=en_US $ catalina.sh start
全局的脚本配置
不推荐该方法。
在$CATALINA_HOME/bin
下创建脚本文件setenv
。该文本会在Tomcat启动时被调用。
例:
#!/bin/bash JVM_MAX_MEM=$(free -m|awk '/Mem/{print$2-1300}') JVM_AGG_MAX_MEM=$(echo $JVM_MAX_MEM |awk '{print $0 * 0.7}') JVM_AGG_MIN_MEM=$(echo $JVM_MAX_MEM |awk '{print $0 * 0.2}') MY_IP=$(ifconfig eth0 |awk -F '[ |:]+' '/inet /{print $4}') if [[ -z $JVM_MAX_MEM || $JVM_MAX_MEM -lt 1024 ]] ;then JVM_AGG_MAX_MEM=1024 JVM_AGG_MIN_MEM=1024 fi JAVA_OPTS="-server -XX:+AggressiveOpts -XX:+DoEscapeAnalysis \ -Xmx${JVM_AGG_MAX_MEM}m \ -Xms${JVM_AGG_MIN_MEM}m \ -Xmn512m \ -Xss512K \ -XX:PermSize=128M \ -XX:MaxPermSize=256M \ -XX:SurvivorRatio=8 \ -XX:+UseCompressedOops \ -XX:+UseParNewGC \ -XX:+UseConcMarkSweepGC \ -XX:+CMSClassUnloadingEnabled \ -XX:+UseCMSCompactAtFullCollection \ -XX:CMSFullGCsBeforeCompaction=0 \ -XX:+CMSParallelRemarkEnabled \ -XX:+DisableExplicitGC \ -XX:+UseCMSInitiatingOccupancyOnly \ -XX:CMSInitiatingOccupancyFraction=75 \ -XX:SoftRefLRUPolicyMSPerMB=0 \ "
系统启动脚本
结合initd
工具的系统服务脚本:
#!/bin/bash # SCRIPT: tomcat # AUTHOR: Ctrip SerweiXu xu.wei@ctrip.com # DATE: 06-11-2013 # REV: 1.0 ### BEGIN INIT INFO # Provides: tomcat7 # Required-Start: $network $syslog # Required-Stop: $network $syslog # Default-Start: # Default-Stop: # Description: Release implementation for Servlet 2.5 and JSP 2.1 # Short-Description: start , stop and thread dump tomcat # chkconfig: - 80 20 # ## Source function library. . /etc/rc.d/init.d/functions export JAVA_HOME=/usr/java/jdk1.7.0_51 export PATH=$JAVA_HOME/bin:$PATH TOMCAT_HOME=/opt/app/tomcat TOMCAT_USER=deploy TOMCAT_LOG_LOCAL=/opt/logs/tomcat SHUTDOWN_WAIT=3 DATESTAMP=`date "+%Y-%m-%d_%H-%M-%S"` tomcat_pid=$( ps aux | grep -i tomcat|grep org.apache.catalina.startup.Bootstrap | grep -v grep | awk '{ print $2 }') if [[ -r $TOMCAT_HOME/bin/setenv.sh ]];then . $TOMCAT_HOME/bin/setenv.sh fi [[ -z $USER ]] && USER=$(/usr/bin/id -un) _start_action () { if [[ $USER == "root" ]];then /bin/su -p -s /bin/sh $TOMCAT_USER $TOMCAT_HOME/bin/startup.sh elif [[ $USER == "deploy" ]];then /bin/sh $TOMCAT_HOME/bin/startup.sh else echo "tomcat only root or deploy run! ....." exit fi } _tdump_action () { [[ ! -z $1 ]] && $argv1 = $1 if [[ $USER == "root" ]];then su -c "$JAVA_HOME/bin/jstack $argv1 $pid" $TOMCAT_USER >${TOMCAT_LOG_LOCAL}/${DATESTAMP}_thread_dump_$pid.log 2>&1 elif [[ $USER == "deploy" ]];then $JAVA_HOME/bin/jstack $argv1 $pid >${TOMCAT_LOG_LOCAL}/${DATESTAMP}_thread_dump_$pid.log 2>&1 fi } tdump() { pid=${tomcat_pid} if [ -n "$pid" ] then _tdump_action echo "The dump file is generated in the ${TOMCAT_LOG_LOCAL}/${DATESTAMP}_thread_dump_$pid.log ." grep "The -F option can be used" ${TOMCAT_LOG_LOCAL}/${DATESTAMP}_thread_dump_${pid}.log >> /dev/null 2>&1 if [ $? -eq 0 ]; then echo "Trigger dump by focre mode!." ForceFlag="-F" _tdump_action -F echo "The dump file is generated in the ${TOMCAT_LOG_LOCAL}/${DATESTAMP}_thread_dump_${pid}.log ." else echo "" fi else echo 'Tomcat is not running.' fi } start() { if [[ -f "/proc/${tomcat_pid}/statm" ]];then echo "Tomcat is already runnaing (pid: $tomcat_pid)" exit 0; fi _start_action return 0 } stop() { if [[ -n "$tomcat_pid" ]];then /bin/sh $TOMCAT_HOME/bin/shutdown.sh sleep $SHUTDOWN_WAIT fi echo "Tomcat is stopped..." return 0 } case $1 in tdump) tdump ;; start) start $2 ;; stop) stop ;; restart) stop sleep 3 start ;; status) if [ -f "/proc/$tomcat_pid/statm" ] then echo "tomcat (pid $tomcat_pid) is running..." else echo "tomcat is stopped" fi ;; *) echo "Usage: $0 {start|stop|status|tdump|restart} [jvmsize]" exit 1 esac exit 0
管理领域、角色及用户
领域(Realm)
领域是角色、用户、密码三种信息的结合。Tomcat提供了几种默认的领域实现, 它们用不同的机制来存储这些信息:
-
UserDatabaseRealm:从内存中取得领域信息。只有在容器启动时从配置文件
$CATALINA_HOME/conf/tomcat-users.xml
中读取领域信息,初始化到内存里。 -
JDBCRealm:领域信息在数据库里。
server.xml
中配置对应数据的连接参数。 - JNDIRealm:领域信息在LDAP目录中。
- JAASRealm:领域信息由Java验证与授权服务 (Java Authentication and Authorization Service)管理。
Tomcat容器自带的安全防护
-
基本验证:当
web.xml
中auth-method
值为BASIC
,每次浏览器访问受保护资源, Tomcat会要求浏览器提供用户名和密码。(注意:这个并不是HTTP的基本验证)。 -
摘要验证:当
web.xml
中auth-method
值为DIGEST
。server.xml
中的Realm
设定也要更改。 - 表单验证:提供一个登录页面。
- Client-Cert验证:HTTPS实现,以浏览器的X.509数字证书认证。
控制会话
Tomcat支持可配置的会话管理器(Session Managers)。并且提供Session Store 支持存储与加载会话。
Session Manager在server.xml
中配置:
<Manager className="som.manager.implementation.className customAttribute1="some custom value" customAttribute2="some other custom value" />
StandardManager
如果没有指定会话管理器,那么默认的会话管理器是StandardManager。
会话信息会保存在磁盘上:
$CATALINA_HOME/work/Catalina/<hostname>/<webapp-name>/SESSIONS.ser
如果Tomcat非正常终止(如kill -9
等),因为来没有存盘会话会丢失。
PersistentManager
在Tomcat 5中还是实现性的功能,PersistenManager把会话存入Sessions Store。 结合FileStore把会话存入文件,JDBCStore把会话存入数据库。
自动重新部署Servlet
开发过程中自动重部署修改过的Servlet是个方便的功能,但生产环境这样做开销太大了。
修改对应WebAppweb.xml
文件的Context
元素中设定reloadable
属性并重启Tomcat。
这样也可以在Manager
应用程序中手动重载工程。
Tomcat Admin webapp
$CATALINA_HOME/conf/tomcat-users.xml
:
<?xml version='1.0' encoding='utf-8'?> <role rolename="role1"/> <user username="admin" password="admin" roles="admin-gui,manager-gui,manager-script,manager-jmx,manager-status" /> <user username="role1" password="role1" roles="role1" /> </tomcat-users>
管理程序的入口为: http://localhost:8080/manager/status
开启JVM调试
JVM 激活远程调试的启动参数有JPDA_OPTS
,CATALINA_OPTS
和JAVA_OPTS
。
其中JAVA_OPTS
是通常不建议使用的, 因为基于JAVA_OPTS
的参数设定会暴露给所有的
JVM 应用, 而CATALINA_OPTS
定义的设定值限制在Tomcat内。
使用JPDA_OPTS
在CATALINA_HOME/bin
目录下创建可执行脚本文件setenv.sh
( Windows 创建setenv.bat
),
加入内容:
Linux setenv.sh
:
export JPDA_OPTS="-agentlib:jdwp=transport=dt_socket,address=1043,server=y,suspend=n"
Windows setenv.bat
set JPDA_OPTS="-agentlib:jdwp=transport=dt_socket,address=1043,server=y,suspend=n"
当然上面的设置也可以直接放到catalina.sh
(catalina.bat )内,
但是有个setevn.*
额外的配置文件一直是最佳选择, tomcat会自动读取。
部署Java Web应用
Tomcat的配置把Web应用称为context
。配置文件以XML文件的形式放对应的目录中:
$CATALINA_HOME/conf/[EngineName]/[HostName]
主机(Host)
Web应用必须属于一个主机,主机代表访问应用时完整的域名或是IP地址。
默认的主机名是localhost
。
server.xml
中的Host
节点配置主机:
<Host name="groovywigs.com" appBase="webapps" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false"> <!-- 这里是groovywigs.com主目录的Context元素 --> </Host> <!-- 默认虚拟主机localhost --> <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false"> <!-- ... --> </Host>
-
autoDeploy
:热布署。 -
deployOnStartup
:Tomcat启动时重新布署一次系统(不管是不是已经热布署过)。
当autoDeploy
与deployOnStartup
都打开时,可能会出现应用被重复布署两次的情况:
自动布署一次,重启时又布署一次。
以目录形式布署
配置可以放在两个地方:
-
$CATALINA_HOME/conf/server.xml
中增加一个Context
节点。 -
$CATALINA_HOME/conf/<EngineName>/<HostName>/
目录中增加一个XML文件。
方法一:server.xml(推荐)
在Host
下添加一个Context
节点:
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="false" xmlValidation="false" xmlNamespaceAware="false"> <Context docBase="my-webapp" path="/my-webapp" /> </Host>
-
docBase
:程序文件在webapp下的目录。 -
path
:URL中访问应用的位置。
映射应用的URL为ROOT
如果要把path
映射为Root URL(/
),不存在以下文件(如果有的话删除就可以):
$CATALINA_HOME/conf/<EngineName>/<HostName>/ROOT.xml
然后设置Context
的path
为""
:
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="false" xmlValidation="false" xmlNamespaceAware="false"> <Context docBase="my-webapp" path="" /> </Host>
方法二:Contex XML
不用完整的server.xml
文件,只是其中Context
段落。
$CATALINA_HOME/conf/<EngineName>/<HostName>/
目录中增加一个XML文件。
例,$CATALINA_HOME/conf/<EngineName>/<HostName>/admin.xml
:
<Context docBase="${catalina.home}/server/webapps/admin" privileged="true" antiResourceLocking="false" antiJARLocking="false"> </Context>
另一个例子,如果程序在/opt/my-webapp/
,映射到URL为my-webapp
,
要指定配置文件名为:
$CATALINA_HOME/conf/<EngineName>/<HostName>/my-webapp.xml
<Context docBase="/opt/myweb-app"> </Context>
布署WAR文件
配置可以放在两个地方:
-
$CATALINA_HOME/conf/server.xml
中增加一个Context
节点。 -
$CATALINA_HOME/conf/<EngineName>/<HostName>/
目录中增加一个XML文件。
方法一:server.xml(推荐)
在Host
下添加一个Context
节点:
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="false" xmlValidation="false" xmlNamespaceAware="false"> <Context docBase="my-webapp.war" path="/my-webapp" /> </Host>
-
docBase
:程序文件在webapp下的位置。 -
path
:URL中访问应用的位置。
映射应用的URL为ROOT
如果要把path
映射为Root URL(/
),不存在以下文件(如果有的话删除就可以):
$CATALINA_HOME/conf/<EngineName>/<HostName>/ROOT.xml
然后设置Context
的path
为""
:
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="false" xmlValidation="false" xmlNamespaceAware="false"> <Context docBase="my-webapp.war" path="" /> </Host>
方法二:Contex XML
不用完整的server.xml
文件,只是其中Context
段落。
$CATALINA_HOME/conf/<EngineName>/<HostName>/
目录中增加一个XML文件。
XML文件的文件名就是对应的URL路径,如果要对应URL根目录则文件名应该为ROOT
。
例,$CATALINA_HOME/conf/<EngineName>/<HostName>/admin.xml
:
<Context docBase="${catalina.home}/server/webapps/admin" privileged="true" antiResourceLocking="false" antiJARLocking="false"> </Context>
另一个例子,如果程序在/opt/my-webapp/
,映射到URL为my-webapp
,
要指定配置文件名为:
$CATALINA_HOME/conf/<EngineName>/<HostName>/my-webapp.xml
<Context docBase="/opt/myweb-app.war"> </Context>
配置服务:systemd
创建/etc/systemd/system/tomcat.service
服务cd /etc/system/system
[Unit] Description=ApacheTomcat Web Application Container After=syslog.targetnetwork.target [Service] Type=forking Environment=JAVA_HOME=/usr/local/jdk-11.0.1 Environment=CATALINA_PID=/opt/tomcat/temp/tomcat.pid Environment=CATALINA_HOME=/opt/tomcat Environment=CATALINA_BASE=/opt/tomcat Environment='CATALINA_OPTS=-Xms512M-Xmx1024M -server -XX:+UseParallelGC' Environment='JAVA_OPTS=-Djava.awt.headless=true-Djava.security.egd=file:/dev/./urandom' ExecStart=/opt/tomcat/bin/startup.sh ExecStop=/bin/kill-15 $MAINPID User=tomcat Group=tomcat UMask=0007 RestartSec=10 Restart=always [Install] WantedBy=multi-user.target
启动tomcat服务:
systemctl daemon-reload systemctl enable tomcat systemctl start tomcat
常见错误排除
日志分析
-
日志配置
conf/logging.properties
,调整各个类的输出级别。 -
Tomcat的系统日志输出在
logs/catalina.out
。
调试HTTP交互
用telnet调试HTTP的302
重定向请求:
$ telnet localhost 80 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. GET / HTTP/1.0 HTTP/1.1 302 Moved Temporarily Content-Type: text/html;charset=utf-8 Date: Thu, 27 Sep 2007 15:21:35 GMT Location: http://localhost:8080/index.html Server: Apache-Coyote/1.1 Connection: close <html> <head> <title>Tomcat Error Report</title> </head> <body bgcolor="white"> <br><br> <h1>HTTP Status 302 - Moved Temporarily</h1> The requested resource (Moved Temporarily) has moved temporarily to a new location. </body> </html> Connection closed by foreign host.
用telnet调试HTTP的200
成功请求:
$ telnet localhost 80 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. GET /index.html HTTP/1.0 HTTP/1.1 200 OK Content-Type: text/html;charset=utf-8 Content-Length: 2836 Date: Thu, 27 Sep 2007 15:33:00 GMT Server: Apache-Coyote/1.1 Last-Modified: Fri, 12 Oct 2001 22:36:50 GMT ETag: "2836-1002926210000" <HTML> <HEAD> <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> <META NAME="GENERATOR" CONTENT="The vi editor from Unix"> <META NAME="Author" CONTENT="Ian Darwin"> <TITLE>Ian Darwin's Webserver On The Road</TITLE> <LINK REL="stylesheet" TYPE="text/css" HREF="/stylesheet.css" TITLE="Style"> </HEAD> <BODY BGCOLOR="#c0d0e0"> <H1>Ian Darwin's Webserver On The Road</H1> # Rest of the HTML not shown here... </BODY></HTML>
使用netcat(即nc
命令)模拟HTTP连接调试:
$ (echo GET / HTTP/1.0; echo "") | nc localhost 80 HTTP/1.1 302 Moved Temporarily Content-Type: text/html;charset=utf-8 Date: Thu, 27 Sep 2007 15:21:47 GMT Location: http://localhost:8080/index.html Server: Apache-Coyote/1.1 Connection: close <html> <head> <title>Tomcat Error Report</title> </head> <body bgcolor="white"> <br><br> <h1>HTTP Status 302 - Moved Temporarily</h1> The requested resource (Moved Temporarily) has moved temporarily to a new location. </body> </html>
用RequestDumperValue来调试
conf/server.xml
中在Host
或Context
里加打开RequestDumperValue调试:
<Valve className="org.apache.catalina.valves.RequestDumperValve" />
然后在Server
、Host
、Context
的日志文件中会有详细的信息。
每个请求的信息用一串等号分隔开来:
RequestDumperValve[/darwinsys]: =============================================================== RequestDumperValve[/darwinsys]: REQUEST URI =/darwinsys/index.jsp RequestDumperValve[/darwinsys]: authType=null RequestDumperValve[/darwinsys]: characterEncoding=null RequestDumperValve[/darwinsys]: contentLength=-1 RequestDumperValve[/darwinsys]: contentType=null RequestDumperValve[/darwinsys]: contextPath=/darwinsys RequestDumperValve[/darwinsys]: cookie=JSESSIONID=C04FE083F247D0C7F24174AA8B78B526 RequestDumperValve[/darwinsys]: header=connection=Keep-Alive RequestDumperValve[/darwinsys]: header=user-agent=Mozilla/5.0 (compatible; Konqueror/2.2.2; OpenBSD 3.1; X11; i386) RequestDumperValve[/darwinsys]: header=accept=text/*, image/jpeg, image/png, image/*, */* RequestDumperValve[/darwinsys]: header=accept-encoding=x-gzip, gzip, identity RequestDumperValve[/darwinsys]: header=accept-charset=Any, utf-8, * RequestDumperValve[/darwinsys]: header=accept-language=en RequestDumperValve[/darwinsys]: header=host=localhost:8080 RequestDumperValve[/darwinsys]: header=cookie=JSESSIONID=C04FE083F247D0C7F24174AA8B78B526 RequestDumperValve[/darwinsys]: header=authorization=Basic aWFkbWluOmZyZWRvbmlh RequestDumperValve[/darwinsys]: locale=en RequestDumperValve[/darwinsys]: method=GET RequestDumperValve[/darwinsys]: pathInfo=null RequestDumperValve[/darwinsys]: protocol=HTTP/1.1 RequestDumperValve[/darwinsys]: queryString=null RequestDumperValve[/darwinsys]: remoteAddr=127.0.0.1 RequestDumperValve[/darwinsys]: remoteHost=127.0.0.1 RequestDumperValve[/darwinsys]: remoteUser=null RequestDumperValve[/darwinsys]: requestedSessionId=C04FE083F247D0C7F24174AA8B78B526 RequestDumperValve[/darwinsys]: scheme=http RequestDumperValve[/darwinsys]: serverName=localhost RequestDumperValve[/darwinsys]: serverPort=8080 RequestDumperValve[/darwinsys]: servletPath=null RequestDumperValve[/darwinsys]: isSecure=false RequestDumperValve[/darwinsys]: ------------------------------------------------- -------- ------ RequestDumperValve[/darwinsys]: ------------------------------------------------- -------- ------ RequestDumperValve[/darwinsys]: authType=null RequestDumperValve[/darwinsys]: contentLength=-1 RequestDumperValve[/darwinsys]: contentType=text/html;ISO-8859-1 RequestDumperValve[/darwinsys]: cookie=JSESSIONID=3042D12AD0B976B9EB83F3ECDDFD095F; domain=null; path=/darwinsys RequestDumperValve[/darwinsys]: header=Content-Type=text/html;ISO-8859-1 RequestDumperValve[/darwinsys]: header=Connection-Type=chunked RequestDumperValve[/darwinsys]: header=Date=Thu, 27 Sep 2007 17:11:31 GMT RequestDumperValve[/darwinsys]: header=Server=Apache-Coyote/1.1 RequestDumperValve[/darwinsys]: header=Set-Cookie=text/html;ISO-8859- 1 RequestDumperValve[/darwinsys]: header=Set- Cookie=JSESSIONID=3042D12AD0B976B9EB83F3ECDDFD095F; Path=/darwinsys RequestDumperValve[/darwinsys]: header=Date=Thu, 27 Sep 2007 17:11:31 GMT RequestDumperValve[/darwinsys]: header=Server=Apache-Coyote/1.1 RequestDumperValve[/darwinsys]: message=null RequestDumperValve[/darwinsys]: remoteUser=null RequestDumperValve[/darwinsys]: status=200 RequestDumperValve[/darwinsys]: ============================================================
Tomcat无法退出
查找Tomcat的进程:
ps auwwx | grep java | grep org.apache.catalina.startup.Bootstrap
以-SIGQUIT
退出进程,这样执行线程的信息记录到catalina.out
里。
比如,当查到进程号是456
时:
kill -SIGQUIT 456
查看catalina.out
里的线程信息:
Sep 27, 2007 9:57:36 PM org.apache.catalina.startup.Catalina start INFO: Server startup in 1286 ms Full thread dump Java HotSpot(TM) 64-Bit Server VM (1.6.0_b105 mixed mode, sharing): "TP-Monitor" daemon prio=1 tid=0x00002aaaaec5d700 nid=0x70b6 in Object.wait() [0x00000000412d3000..0x00000000412d3d00] at java.lang.Object.wait(Native Method) - waiting on <0x00002aff518c50b8> (a org.apache.tomcat.util.threads. ThreadPool$MonitorRunnable) at org.apache.tomcat.util.threads.ThreadPool$MonitorRunnable.run (ThreadPool.java: 561) - locked <0x00002aff518c50b8> (a org.apache.tomcat.util.threads. ThreadPool$MonitorRunnable) at java.lang.Thread.run(Thread.java:595) "TP-Processor4" daemon prio=1 tid=0x00002aaaae0a3e80 nid=0x70b5 runnable [0x00000000411d2000..0x00000000411d2c80] at java.net.PlainSocketImpl.socketAccept(Native Method) at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:384) - locked <0x00002aff51883d28> (a java.net.SocksSocketImpl) at java.net.ServerSocket.implAccept(ServerSocket.java:450) at java.net.ServerSocket.accept(ServerSocket.java:421) at org.apache.jk.common.ChannelSocket.accept(ChannelSocket.java:306) at org.apache.jk.common.ChannelSocket.acceptConnections (ChannelSocket.java:660) at org.apache.jk.common.ChannelSocket$SocketAcceptor.runIt (ChannelSocket.java: 870) at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run (ThreadPool.java: 686) at java.lang.Thread.run(Thread.java:595) "TP-Processor3" daemon prio=1 tid=0x00002aaaae0a3090 nid=0x70b4 in Object.wait() [0x00000000410d1000..0x00000000410d1c00] at java.lang.Object.wait(Native Method) - waiting on <0x00002aff518c4538> (a org.apache.tomcat.util.threads. ThreadPool$ControlRunnable) at java.lang.Object.wait(Object.java:474) at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run (ThreadPool.java: 658) - locked <0x00002aff518c4538> (a org.apache.tomcat.util.threads. ThreadPool$ControlRunnable) at java.lang.Thread.run(Thread.java:595)
检查这些线程有哪些是创建的非守护线程(non-daemon), 只有守护线程能在Tomcat关闭时自动退出。非守护线程在没有执行完之前是不会退出的。