catalina.sh是Tomcat的主要核心脚本,启动脚本,停止脚本等其他的脚本都会调用这个脚本,我们这一节就来深入分析这个脚本。
1.shell变量
在catalina.sh脚本的最开始,开始设置了一些shell变量,这些:

CATALINA_HOME:众所周知,这个环境变量是Tomcat的安装目录。
CATALINA_BASE:一定要区分这个CATALINA_BASE和这个CATALINA_HOME,二者是完全不同的,CATALINA_BASE是Tomcat的工作目录,也就是说CATALINA_HOME指的是bin目录和lib目录,这两个目录是公有目录信息,而CATALINA_BASE中的内容为
其它目录conf、logs、temp、webapps和work,这些目录每一个Tomcat实例有一份,这两个参数也就构成了Tomcat的多实例配置,可以看到下面一个典型多实例的结构:

其中a.ttlsa.com是实例1,b.ttlsa.com是实例2,这两个实例分别安装在不同的目录中,每一个实例中找对应的lib包的时候,直接找到CATALINA_HOME的lib下的jar包,另外在配置Tomcat多实例的时候,需要对每一个实例的配置文件的端口进行都改,启动脚本也需要进行修改,例如在每一个实例中创建tomcat.sh,每一个脚本的内容可以指向CATALINA_HOME/bin目录中的功能

启动和停止可以看到直接还是调用CATALINA_HOME的bin目录下的脚本,二者各司其职;
当不配置多实例的时候,CATALINA_BASE就是CATALINA_HOME,二者没有区别。
CATALINA_OUT:这个参数是tomcat的输出日志,老版本的catalina.sh脚本中,当设置这个环境变量的时候,会将Tomcat的日志都会输出到$CATALINA_BASE/logs/catalina.out中去:

这样的话,Tomcat的stdout and stderr的redirect日志非常的大,也不利于管理,所以这个参数所以是可选参数,而目前可以看到Tomcat8的日志默认按照天来产生日志:

CATALINA_OPTS:这个变量是Tomcat自己内部使用的,其实这个变量就是"start", "run" or "debug"这些命令,并不作为环境变量对外提供,在启动java进程的时候,这个变量作为参数传递。
CATALINA_TMPDIR:也是可选的Tomcat的临时目录,在Tomcat运行过程中,如上传文件,jasper编译等等都需要在临时目录做一下缓冲。
JAVA_HOME:JDK的安装目录。
JRE_HOME:JRE的安装目录,不是JDK的,注意区分。
JAVA_OPTS:在启动Tomcat的JVM进程的时候,经常会向JVM传递一些-D的参数,可以看到在catalina.sh脚本中,-D参数都是集中在这个JAVA_OPTS变量中:

JAVA_ENDORSED_DIRS:endorse目录的作用是可以针对JDK默认自带的一些API做一些替换,当配置这个endorse目录的时候,首先会找endorse目录中的API(lang包除外),对于默认的Tomcat的endorse目录的位置为:$CATALINA_HOME/endorsed。
JPDA_TRANSPORT:定义JPDA的客户端和服务器端的传输方式,默认的值为dt_socket,这相当于双方采用套接字进行通讯。
JPDA_ADDRESS:JPDA绑定的端口。
JPDA_SUSPEND:JPDA是暂停执行当前的进程等待调试者链接上服务器,还是先进行执行然后待调试者连接上如果有断点的话,自动暂停到当前的代码处。
JPDA_OPTS:这个参数是JPDA的参数,当设置这个参数,上面的三个JPDA参数就没有用了。

可以看到上面的catalina.sh中的这段逻辑,非常清晰的看出JPDA的属性实际上最后是加到了CATALINA_OPTS.
CATALINA_PID:
catalina.sh本身支持强制关闭tomcat,但需要一个变量CATALINA_PID,也就是tomcat的进程号,只要我们指定了CATALINA_PID,tomcat启动时就会将进程号写入指定的文件中,这个文件中存放的就是tomcat的进程号,每一次tomcat启动和停止之前,都会直接对这个PID进行操作,在linux上就是对这个PID发信号:

LOGGING_CONFIG:默认的Tomcat的日志采用juli,这个变量可以指定替换下面的
LOGGING_CONFIG="-Djava.util.logging.config.file=$CATALINA_BASE/conf/logging.properties"
LOGGING_MANAGER:这个选项是覆盖Tomcat默认的日志管理器,也就是LogManager
LOGGING_MANAGER="-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager"
2.开放的命令分析

使用方式是 catalina.sh 后面跟cmd命令,这些命令为:
debug:
debug模式是使用JDK自带的JDB工具,例如本地调试 jdb -classpath bin com.xx.Example,这个要求调试的源码和classpath的类都在一台机器上,二者直接进行调试,这块在IDE中我们点击eclipse调试,就是上述的命令进行集成的;
在catalina.sh中,就是以JDB的方式来通过调试来启动Tomcat,这个$_RUNJDB就是JDB的参数,在setclasspath.sh的最后一步判断出JAVA_HOME,赋值的变量:

在catalina.sh中,执行这个jdb的命令:

分为两种方式,一种是带安全管理器的,一种是不带的。
对于JDB的用法,参考http://docs.oracle.com/javase/1.5.0/docs/tooldocs/windows/jdb.html
jpda:
因为最开始JAVA中的JDB工具比较弱,仅仅能做本地调试,因此搞出来一个JPDA,JPDA严格意义上来说,是一个JAVA平台级别的调试体系架构,由3个规范组成,分别是JVMTI(JVM Tool Interface),JDWP(Java Debug Wire Protocol),JDI(Java Debug Interface) :

可以理解JAVA整体上定义了一套协议,用于本地和远程的交互,并在上层提供了JDI规范作为工具支撑的规范.。

直接在CATALINA_OPTS中加上上述的一系列参数,JPDA debugger就启动起来了,然后客户端通过JDI来远程调试虚拟机。
值得一提的是,JDB后来也实现了JPDA中的JDI规范,大白话来讲,现在JDB也能进行远程调试了。
所以,当你执行catalina.sh jpda run的时候,本地的8000端口就可以被远程调试了。
run:

run命令与jdb的命令几乎是一样的,只不过一个是走得jdb本地调试模式,一个是直接执行java
start:
start主要和run的区别在于,如果设置了$CATALINA_PID的话,首先通过PS命令,查看当前的进程号,并
将当前的进程号写入到对应$CATALINA_PID文件中:

第二步启动的操作,和Tomcat的操作和run命令一样。
stop:
stop的操作比start还要复杂一些,它也是对$CATALINA_PID文件中的pid进行校验,如果没有的话,直接会报错,如果有的话,尝试着通过kill命令发信号给这个进程:

当属性为-force的时候,直接kill -9

stop还能给定一个秒数,也就是先睡个几秒,默认是5s:

configtest和version命令在前面已经分析过了,一个是做server.xml格式校验的,一个是返回当前Tomcat的信息的,这里不再缀余了;
总结一下,可以看到上述这些命令的实现都是bootstrap.jar来实现的,
下一节我们会重点分析一下启动包。




