深入理解 Tomcat(七)源码剖析 Tomcat 完整启动过程

转载自:https://blog.csdn.net/qq_38182963/article/details/78660787

前言

这是我们分析 Tomcat 的第七篇文章,前面我们依据启动过程理解了类加载过程,生命周期组件,容器组件等。基本上将启动过程拆的七零八落,分析的差不多了, 但是还没有从整体的视图下来分析Tomcat 的启动过程。因此,这篇文章的任务就是这个,我们想将Tomcat的启动过程彻底的摸清,把它最后一件衣服扒掉。然后我们就分析连接器和URL请求了,不再留恋这里了。

好吧。我们开始吧。

说到Tomcat的启动,我们都知道,我们每次需要运行tomcat/bin/startup.sh这个脚本,而这个脚本的内容到底是什么呢?我们来看看。

1. startup.sh 脚本内容

#!/bin/sh
os400=false
case "`uname`" in
OS400*) os400=true;;
esac

# resolve links - $0 may be a softlink
PRG="$0"

while [ -h " P R G &lt; / s p a n &gt; &quot; &lt; / s p a n &gt; ] ; &lt; s p a n c l a s s = &quot; h l j s − k e y w o r d &quot; &gt; d o &lt; / s p a n &gt; l s = ‘ l s − l d &lt; s p a n c l a s s = &quot; h l j s − s t r i n g &quot; &gt; &quot; &lt; s p a n c l a s s = &quot; h l j s − v a r i a b l e &quot; &gt; PRG&lt;/span&gt;&quot;&lt;/span&gt; ] ; &lt;span class=&quot;hljs-keyword&quot;&gt;do&lt;/span&gt; ls=`ls -ld &lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-variable&quot;&gt; PRG</span>"</span>];<spanclass="hljskeyword">do</span>ls=lsld<spanclass="hljsstring">"<spanclass="hljsvariable">PRG"link=expr "KaTeX parse error: Expected 'EOF', got '&' at position 51: …js-string">'.*-&̲gt; \(.*\)'<span class="hljs-keyword">if</span> expr <span class="hljs-string">"<span class="hljs-variable">$link</span>"</span> : <span class="hljs-string">'/.*'</span> &gt; /dev/null; <span class="hljs-keyword">then</span> PRG=<span class="hljs-string">"<span class="hljs-variable">$link</span>"</span> <span class="hljs-keyword">else</span> PRG=dirname P R G &lt; / s p a n &gt; &quot; &lt; / s p a n &gt; ‘ / &lt; s p a n c l a s s = &quot; h l j s − s t r i n g &quot; &gt; &quot; &lt; s p a n c l a s s = &quot; h l j s − v a r i a b l e &quot; &gt; PRG&lt;/span&gt;&quot;&lt;/span&gt;`/&lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-variable&quot;&gt; PRG</span>"</span>/<spanclass="hljsstring">"<spanclass="hljsvariable">link
fi
done

PRGDIR=dirname <span class="hljs-string">"<span class="hljs-variable">$PRG</span>"</span>
EXECUTABLE=catalina.sh

# Check that target executable exists
if KaTeX parse error: Expected 'EOF', got '#' at position 83: …"hljs-comment">#̲ -x will Only w…PRGDIR"/ E X E C U T A B L E &lt; / s p a n &gt; &quot; &lt; / s p a n &gt; ] ; &lt; s p a n c l a s s = &quot; h l j s − k e y w o r d &quot; &gt; t h e n &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − b u i l t i n &quot; &gt; e c h o &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − s t r i n g &quot; &gt; &quot; C a n n o t f i n d &lt; s p a n c l a s s = &quot; h l j s − v a r i a b l e &quot; &gt; EXECUTABLE&lt;/span&gt;&quot;&lt;/span&gt; ]; &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;Cannot find &lt;span class=&quot;hljs-variable&quot;&gt; EXECUTABLE</span>"</span>];<spanclass="hljskeyword">then</span><spanclass="hljsbuiltin">echo</span><spanclass="hljsstring">"Cannotfind<spanclass="hljsvariable">PRGDIR/$EXECUTABLE
echo “The file is absent or does not have execute permission”
echo “This file is needed to run this program”
exit 1
fi
fi

exec P R G D I R &lt; / s p a n &gt; &quot; &lt; / s p a n &gt; / &lt; s p a n c l a s s = &quot; h l j s − s t r i n g &quot; &gt; &quot; &lt; s p a n c l a s s = &quot; h l j s − v a r i a b l e &quot; &gt; PRGDIR&lt;/span&gt;&quot;&lt;/span&gt;/&lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-variable&quot;&gt; PRGDIR</span>"</span>/<spanclass="hljsstring">"<spanclass="hljsvariable">EXECUTABLE start $@

楼主删除了一些无用的注释,我们来看看这脚本。该脚本中有2个重要的变量:
1. PRGDIR:表示当前脚本所在的路径
2. EXECUTABLE:catalina.sh 脚本名称
其中最关键的一行代码就是 exec "$PRGDIR"/"$EXECUTABLE" start "$@",表示执行了脚本catalina.sh,参数是start。

2. catalina.sh 脚本实现

然后我们看看catalina.sh 脚本中的实现:

elif [ "$1" = "start" ] ; then

if [ ! -z C A T A L I N A P I D &lt; / s p a n &gt; &quot; &lt; / s p a n &gt; ] ; &lt; s p a n c l a s s = &quot; h l j s − k e y w o r d &quot; &gt; t h e n &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − k e y w o r d &quot; &gt; i f &lt; / s p a n &gt; [ &lt; s p a n c l a s s = &quot; h l j s − o p e r a t o r &quot; &gt; − f &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − s t r i n g &quot; &gt; &quot; &lt; s p a n c l a s s = &quot; h l j s − v a r i a b l e &quot; &gt; CATALINA_PID&lt;/span&gt;&quot;&lt;/span&gt; ]; &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; [ &lt;span class=&quot;hljs-operator&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-variable&quot;&gt; CATALINAPID</span>"</span>];<spanclass="hljskeyword">then</span><spanclass="hljskeyword">if</span>[<spanclass="hljsoperator">f</span><spanclass="hljsstring">"<spanclass="hljsvariable">CATALINA_PID ]; then
if [ -s C A T A L I N A P I D &lt; / s p a n &gt; &quot; &lt; / s p a n &gt; ] ; &lt; s p a n c l a s s = &quot; h l j s − k e y w o r d &quot; &gt; t h e n &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − b u i l t i n &quot; &gt; e c h o &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − s t r i n g &quot; &gt; &quot; E x i s t i n g P I D f i l e f o u n d d u r i n g s t a r t . &quot; &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − k e y w o r d &quot; &gt; i f &lt; / s p a n &gt; [ − r &lt; s p a n c l a s s = &quot; h l j s − s t r i n g &quot; &gt; &quot; &lt; s p a n c l a s s = &quot; h l j s − v a r i a b l e &quot; &gt; CATALINA_PID&lt;/span&gt;&quot;&lt;/span&gt; ]; &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;Existing PID file found during start.&quot;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; [ -r &lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-variable&quot;&gt; CATALINAPID</span>"</span>];<spanclass="hljskeyword">then</span><spanclass="hljsbuiltin">echo</span><spanclass="hljsstring">"ExistingPIDfilefoundduringstart."</span><spanclass="hljskeyword">if</span>[r<spanclass="hljsstring">"<spanclass="hljsvariable">CATALINA_PID ]; then
PID=cat <span class="hljs-string">"<span class="hljs-variable">$CATALINA_PID</span>"</span>
ps -p $PID >/dev/null 2>&1
if [ ? &lt; s p a n c l a s s = &quot; h l j s − o p e r a t o r &quot; &gt; − e q &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − n u m b e r &quot; &gt; 0 &lt; / s p a n &gt; ] ; &lt; s p a n c l a s s = &quot; h l j s − k e y w o r d &quot; &gt; t h e n &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − b u i l t i n &quot; &gt; e c h o &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − s t r i n g &quot; &gt; &quot; T o m c a t a p p e a r s t o s t i l l b e r u n n i n g w i t h P I D &lt; s p a n c l a s s = &quot; h l j s − v a r i a b l e &quot; &gt; ? &lt;span class=&quot;hljs-operator&quot;&gt;-eq&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; ] ; &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;Tomcat appears to still be running with PID &lt;span class=&quot;hljs-variable&quot;&gt; ?<spanclass="hljsoperator">eq</span><spanclass="hljsnumber">0</span>];<spanclass="hljskeyword">then</span><spanclass="hljsbuiltin">echo</span><spanclass="hljsstring">"TomcatappearstostillberunningwithPID<spanclass="hljsvariable">PID. Start aborted."
echo “If the following process is not a Tomcat process, remove the PID file and try again:”
ps -f -p P I D &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − k e y w o r d &quot; &gt; e x i t &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − n u m b e r &quot; &gt; 1 &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − k e y w o r d &quot; &gt; e l s e &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − b u i l t i n &quot; &gt; e c h o &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − s t r i n g &quot; &gt; &quot; R e m o v i n g / c l e a r i n g s t a l e P I D f i l e . &quot; &lt; / s p a n &gt; r m &lt; s p a n c l a s s = &quot; h l j s − o p e r a t o r &quot; &gt; − f &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − s t r i n g &quot; &gt; &quot; &lt; s p a n c l a s s = &quot; h l j s − v a r i a b l e &quot; &gt; PID&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;exit&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;Removing/clearing stale PID file.&quot;&lt;/span&gt; rm &lt;span class=&quot;hljs-operator&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-variable&quot;&gt; PID</span><spanclass="hljskeyword">exit</span><spanclass="hljsnumber">1</span><spanclass="hljskeyword">else</span><spanclass="hljsbuiltin">echo</span><spanclass="hljsstring">"Removing/clearingstalePIDfile."</span>rm<spanclass="hljsoperator">f</span><spanclass="hljsstring">"<spanclass="hljsvariable">CATALINA_PID" >/dev/null 2>&1
if [ ? ! = &lt; s p a n c l a s s = &quot; h l j s − n u m b e r &quot; &gt; 0 &lt; / s p a n &gt; ] ; &lt; s p a n c l a s s = &quot; h l j s − k e y w o r d &quot; &gt; t h e n &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − k e y w o r d &quot; &gt; i f &lt; / s p a n &gt; [ − w &lt; s p a n c l a s s = &quot; h l j s − s t r i n g &quot; &gt; &quot; &lt; s p a n c l a s s = &quot; h l j s − v a r i a b l e &quot; &gt; ? != &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; ]; &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; [ -w &lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-variable&quot;&gt; ?!=<spanclass="hljsnumber">0</span>];<spanclass="hljskeyword">then</span><spanclass="hljskeyword">if</span>[w<spanclass="hljsstring">"<spanclass="hljsvariable">CATALINA_PID" ]; then
cat /dev/null > C A T A L I N A P I D &lt; / s p a n &gt; &quot; &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − k e y w o r d &quot; &gt; e l s e &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − b u i l t i n &quot; &gt; e c h o &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − s t r i n g &quot; &gt; &quot; U n a b l e t o r e m o v e o r c l e a r s t a l e P I D f i l e . S t a r t a b o r t e d . &quot; &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − k e y w o r d &quot; &gt; e x i t &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − n u m b e r &quot; &gt; 1 &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − k e y w o r d &quot; &gt; f i &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − k e y w o r d &quot; &gt; f i &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − k e y w o r d &quot; &gt; f i &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − k e y w o r d &quot; &gt; e l s e &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − b u i l t i n &quot; &gt; e c h o &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − s t r i n g &quot; &gt; &quot; U n a b l e t o r e a d P I D f i l e . S t a r t a b o r t e d . &quot; &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − k e y w o r d &quot; &gt; e x i t &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − n u m b e r &quot; &gt; 1 &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − k e y w o r d &quot; &gt; f i &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − k e y w o r d &quot; &gt; e l s e &lt; / s p a n &gt; r m &lt; s p a n c l a s s = &quot; h l j s − o p e r a t o r &quot; &gt; − f &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − s t r i n g &quot; &gt; &quot; &lt; s p a n c l a s s = &quot; h l j s − v a r i a b l e &quot; &gt; CATALINA_PID&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;Unable to remove or clear stale PID file. Start aborted.&quot;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;exit&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;fi&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;fi&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;fi&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;Unable to read PID file. Start aborted.&quot;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;exit&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;fi&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; rm &lt;span class=&quot;hljs-operator&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-variable&quot;&gt; CATALINAPID</span>"</span><spanclass="hljskeyword">else</span><spanclass="hljsbuiltin">echo</span><spanclass="hljsstring">"UnabletoremoveorclearstalePIDfile.Startaborted."</span><spanclass="hljskeyword">exit</span><spanclass="hljsnumber">1</span><spanclass="hljskeyword">fi</span><spanclass="hljskeyword">fi</span><spanclass="hljskeyword">fi</span><spanclass="hljskeyword">else</span><spanclass="hljsbuiltin">echo</span><spanclass="hljsstring">"UnabletoreadPIDfile.Startaborted."</span><spanclass="hljskeyword">exit</span><spanclass="hljsnumber">1</span><spanclass="hljskeyword">fi</span><spanclass="hljskeyword">else</span>rm<spanclass="hljsoperator">f</span><spanclass="hljsstring">"<spanclass="hljsvariable">CATALINA_PID >/dev/null 2>&1
if [ ? ! = &lt; s p a n c l a s s = &quot; h l j s − n u m b e r &quot; &gt; 0 &lt; / s p a n &gt; ] ; &lt; s p a n c l a s s = &quot; h l j s − k e y w o r d &quot; &gt; t h e n &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − k e y w o r d &quot; &gt; i f &lt; / s p a n &gt; [ ! − w &lt; s p a n c l a s s = &quot; h l j s − s t r i n g &quot; &gt; &quot; &lt; s p a n c l a s s = &quot; h l j s − v a r i a b l e &quot; &gt; ? != &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; ]; &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; [ ! -w &lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-variable&quot;&gt; ?!=<spanclass="hljsnumber">0</span>];<spanclass="hljskeyword">then</span><spanclass="hljskeyword">if</span>[!w<spanclass="hljsstring">"<spanclass="hljsvariable">CATALINA_PID" ]; then
echo “Unable to remove or write to empty PID file. Start aborted.”
exit 1
fi
fi
fi
fi
fi

shift
touch $CATALINA_OUT
if [ 1 &lt; / s p a n &gt; &quot; &lt; / s p a n &gt; = &lt; s p a n c l a s s = &quot; h l j s − s t r i n g &quot; &gt; &quot; − s e c u r i t y &quot; &lt; / s p a n &gt; ] ; &lt; s p a n c l a s s = &quot; h l j s − k e y w o r d &quot; &gt; t h e n &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − k e y w o r d &quot; &gt; i f &lt; / s p a n &gt; [ &lt; s p a n c l a s s = &quot; h l j s − v a r i a b l e &quot; &gt; 1&lt;/span&gt;&quot;&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&quot;-security&quot;&lt;/span&gt; ] ; &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; [ &lt;span class=&quot;hljs-variable&quot;&gt; 1</span>"</span>=<spanclass="hljsstring">"security"</span>];<spanclass="hljskeyword">then</span><spanclass="hljskeyword">if</span>[<spanclass="hljsvariable">have_tty -eq 1 ]; then
echo “Using Security Manager”
fi
shift
eval KaTeX parse error: Can't use function '\"' in math mode at position 42: …"hljs-string">"\̲"̲<span class="hl…_RUNJAVA”"
““KaTeX parse error: Can't use function '\"' in math mode at position 22: …G_CONFIG</span>\̲"̲"</span> <span …LOGGING_MANAGER J A V A O P T S &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − v a r i a b l e &quot; &gt; JAVA_OPTS&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt; JAVAOPTS</span><spanclass="hljsvariable">CATALINA_OPTS
-classpath ““KaTeX parse error: Can't use function '\"' in math mode at position 17: …LASSPATH</span>\̲"̲"</span> \ …CATALINA_BASE/conf/catalina.policy””
-Dcatalina.base=”“KaTeX parse error: Can't use function '\"' in math mode at position 21: …INA_BASE</span>\̲"̲"</span> \ …CATALINA_HOME””
-Djava.io.tmpdir=""KaTeX parse error: Can't use function '\"' in math mode at position 23: …A_TMPDIR</span>\̲"̲"</span> \ …@" start
>> $CATALINA_OUT 2>&1 “&”

else
eval KaTeX parse error: Can't use function '\"' in math mode at position 42: …"hljs-string">"\̲"̲<span class="hl…_RUNJAVA"" ““KaTeX parse error: Can't use function '\"' in math mode at position 22: …G_CONFIG</span>\̲"̲"</span> <span …LOGGING_MANAGER J A V A O P T S &lt; / s p a n &gt; &lt; s p a n c l a s s = &quot; h l j s − v a r i a b l e &quot; &gt; JAVA_OPTS&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt; JAVAOPTS</span><spanclass="hljsvariable">CATALINA_OPTS
-classpath ““KaTeX parse error: Can't use function '\"' in math mode at position 17: …LASSPATH</span>\̲"̲"</span> \ …CATALINA_BASE””
-Dcatalina.home=”“KaTeX parse error: Can't use function '\"' in math mode at position 21: …INA_HOME</span>\̲"̲"</span> \ …CATALINA_TMPDIR””
org.apache.catalina.startup.Bootstrap KaTeX parse error: Expected 'EOF', got '\ ' at position 24: …"</span> start \̲ ̲ &gt;&gt; …CATALINA_OUT 2>&1 “&”

fi

if [ ! -z $CATALINA_PID ]; then
echo KaTeX parse error: Expected 'EOF', got '&' at position 3: ! &̲gt; <span class…CATALINA_PID"
fi

echo “Tomcat started.”

该脚本很长,但我们只关心我们感兴趣的:如果参数是 start, 那么执行这里的逻辑,关键再最后一行执行了 org.apache.catalina.startup.Bootstrap "$@" start, 也就是说,执行了我们熟悉的main方法,并且携带了start 参数,那么我们就来看Bootstrap 的main方法是如何实现的。

3. Bootstrap.main 方法实现

    public static void main(String args[]) {
    System.err.println(<span class="hljs-string">"Have fun and Enjoy! cxs"</span>);

    <span class="hljs-comment">// daemon 就是 bootstrap</span>
    <span class="hljs-keyword">if</span> (daemon == <span class="hljs-keyword">null</span>) {
        Bootstrap bootstrap = <span class="hljs-keyword">new</span> Bootstrap();
        <span class="hljs-keyword">try</span> {
            bootstrap.init();
        } <span class="hljs-keyword">catch</span> (Throwable t) {
            handleThrowable(t);
            t.printStackTrace();
            <span class="hljs-keyword">return</span>;
        }
        daemon = bootstrap;
    } <span class="hljs-keyword">else</span> {
        Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
    }

    <span class="hljs-keyword">try</span> {
        String command = <span class="hljs-string">"start"</span>;
        <span class="hljs-keyword">if</span> (args.length &gt; <span class="hljs-number">0</span>) {
            command = args[args.length - <span class="hljs-number">1</span>];
        }
        <span class="hljs-keyword">if</span> (command.equals(<span class="hljs-string">"startd"</span>)) {
            args[args.length - <span class="hljs-number">1</span>] = <span class="hljs-string">"start"</span>;
            daemon.load(args);
            daemon.start();
        }
        <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (command.equals(<span class="hljs-string">"stopd"</span>)) {
            args[args.length - <span class="hljs-number">1</span>] = <span class="hljs-string">"stop"</span>;
            daemon.stop();
        }
        <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (command.equals(<span class="hljs-string">"start"</span>)) {
            daemon.setAwait(<span class="hljs-keyword">true</span>);
            daemon.load(args);
            daemon.start();
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (command.equals(<span class="hljs-string">"stop"</span>)) {
            daemon.stopServer(args);
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (command.equals(<span class="hljs-string">"configtest"</span>)) {
            daemon.load(args);
            <span class="hljs-keyword">if</span> (<span class="hljs-keyword">null</span>==daemon.getServer()) {
                System.exit(<span class="hljs-number">1</span>);
            }
            System.exit(<span class="hljs-number">0</span>);
        } <span class="hljs-keyword">else</span> {
            log.warn(<span class="hljs-string">"Bootstrap: command \""</span> + command + <span class="hljs-string">"\" does not exist."</span>);
        }
    } <span class="hljs-keyword">catch</span> (Throwable t) {
        <span class="hljs-keyword">if</span> (t <span class="hljs-keyword">instanceof</span> InvocationTargetException &amp;&amp;
                t.getCause() != <span class="hljs-keyword">null</span>) {
            t = t.getCause();
        }
        handleThrowable(t);
        t.printStackTrace();
        System.exit(<span class="hljs-number">1</span>);
    }
}</code></pre>

我们看看该方法, 首先 bootstrap.init() 的方法用于初始化类加载器,我们已经分析过该方法了,就不再赘述了,然后我们看下面的try块,默认命令行参数是 start ,但我们刚刚的脚本传的参数就是 start, 因此进入该if块

   else if (command.equals("start")) {
         daemon.setAwait(true);
         daemon.load(args);
         daemon.start();
  1. 设置catalina 的 await 属性为true;
  2. 运行 catalina 的 load 方法。该方法内部主要逻辑是解析server.xml文件,初始化容器。我们已经再生命周期那篇文章中讲过容器的初始化。
  3. 运行 catalina 的 start 方法。也就是启动 tomcat。这个部分我们上次分析了容器启动。但是容器之后的逻辑我们没有分析。今天我们就来看看。

4. Catalina.start 方法

 public void start() {
        if (getServer() == null) {
            load();
        }
        if (getServer() == null) {
            log.fatal("Cannot start server. Server instance is not configured.");
            return;
        }
        long t1 = System.nanoTime();
        // Start the new server
        try {
            getServer().start();
        } catch (LifecycleException e) {
            log.fatal(sm.getString("catalina.serverStartFail"), e);
            try {
                getServer().destroy();
            } catch (LifecycleException e1) {
                log.debug("destroy() failed for failed Server ", e1);
            }
            return;
        }
        long t2 = System.nanoTime();
        if(log.isInfoEnabled()) {
            log.info("Server startup in " + ((t2 - t1) / 1000000) + " ms");
        }
        if (useShutdownHook) {
            if (shutdownHook == null) {
                shutdownHook = new CatalinaShutdownHook();
            }
            Runtime.getRuntime().addShutdownHook(shutdownHook);
        <span class="hljs-comment">// If JULI is being used, disable JULI's shutdown hook since</span>
        <span class="hljs-comment">// shutdown hooks run in parallel and log messages may be lost</span>
        <span class="hljs-comment">// if JULI's hook completes before the CatalinaShutdownHook()</span>
        LogManager logManager = LogManager.getLogManager();
        <span class="hljs-keyword">if</span> (logManager <span class="hljs-keyword">instanceof</span> ClassLoaderLogManager) {
            ((ClassLoaderLogManager) logManager).setUseShutdownHook(
                    <span class="hljs-keyword">false</span>);
        }
    }
    <span class="hljs-keyword">if</span> (await) {
        await();
        stop();
    }
}</code></pre>

该方法我们上次分析到了 getServer().start() 这里,也就是容器启动的逻辑,我们不再赘述。
今天我们继续分析下面的逻辑。主要逻辑是:

 if (useShutdownHook) {
            if (shutdownHook == null) {
                shutdownHook = new CatalinaShutdownHook();
            }
            Runtime.getRuntime().addShutdownHook(shutdownHook);
        <span class="hljs-comment">// If JULI is being used, disable JULI's shutdown hook since</span>
        <span class="hljs-comment">// shutdown hooks run in parallel and log messages may be lost</span>
        <span class="hljs-comment">// if JULI's hook completes before the CatalinaShutdownHook()</span>
        LogManager logManager = LogManager.getLogManager();
        <span class="hljs-keyword">if</span> (logManager <span class="hljs-keyword">instanceof</span> ClassLoaderLogManager) {
            ((ClassLoaderLogManager) logManager).setUseShutdownHook(
                    <span class="hljs-keyword">false</span>);
        }
    }
    <span class="hljs-keyword">if</span> (await) {
        await();
        stop();
    }</code></pre>

可以看到是 Runtime.getRuntime().addShutdownHook(shutdownHook)方法。那么这个方法的作用是什么呢?JDK 文档是这样说的:

注册新的虚拟机来关闭钩子。
只是一个已初始化但尚未启动的线程。虚拟机开始启用其关闭序列时,它会以某种未指定的顺序启动所有已注册的关闭钩子,并让它们同时运行。运行完所有的钩子后,如果已启用退出终结,那么虚拟机接着会运行所有未调用的终结方法。最后,虚拟机会暂停。注意,关闭序列期间会继续运行守护线程,如果通过调用方法来发起关闭序列,那么也会继续运行非守护线程。

简单来说,如果用户的程序出现了bug, 或者使用control + C 关闭了命令行,那么就需要做一些内存清理的工作。该方法就会再虚拟机退出时做清理工作。再ApplicationShutdownHooks 类种维护着一个IdentityHashMap

5. CatalinaShutdownHook.run 线程方法实现

 protected class CatalinaShutdownHook extends Thread {
        @Override
        public void run() {
            try {
                if (getServer() != null) {
                    Catalina.this.stop();
                }
            } catch (Throwable ex) {
                ExceptionUtils.handleThrowable(ex);
                log.error(sm.getString("catalina.shutdownHookFail"), ex);
            } finally {
                // If JULI is used, shut JULI down *after* the server shuts down
                // so log messages aren't lost
                LogManager logManager = LogManager.getLogManager();
                if (logManager instanceof ClassLoaderLogManager) {
                    ((ClassLoaderLogManager) logManager).shutdown();
                }
            }
        }
    }

该线程是Catalina的内部类,方法逻辑是,如果Server容器还存在,就是执行Catalina的stop方法用于停止容器。(为什么要用Catalina.this.stop 呢?因为它继承了Thread,而Thread也有一个stop方法,因此需要显式的指定该方法)最后关闭日志管理器。我们看看stop方法的实现:

6. Catalina.stop 方法实现:

public void stop() {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">// Remove the ShutdownHook first so that server.stop()</span>
        <span class="hljs-comment">// doesn't get invoked twice</span>
        <span class="hljs-keyword">if</span> (useShutdownHook) {
            Runtime.getRuntime().removeShutdownHook(shutdownHook);

            <span class="hljs-comment">// If JULI is being used, re-enable JULI's shutdown to ensure</span>
            <span class="hljs-comment">// log messages are not lost</span>
            LogManager logManager = LogManager.getLogManager();
            <span class="hljs-keyword">if</span> (logManager <span class="hljs-keyword">instanceof</span> ClassLoaderLogManager) {
                ((ClassLoaderLogManager) logManager).setUseShutdownHook(
                        <span class="hljs-keyword">true</span>);
            }
        }
    } <span class="hljs-keyword">catch</span> (Throwable t) {
        ExceptionUtils.handleThrowable(t);
        <span class="hljs-comment">// This will fail on JDK 1.2. Ignoring, as Tomcat can run</span>
        <span class="hljs-comment">// fine without the shutdown hook.</span>
    }

    <span class="hljs-comment">// Shut down the server</span>
    <span class="hljs-keyword">try</span> {
        Server s = getServer();
        LifecycleState state = s.getState();
        <span class="hljs-keyword">if</span> (LifecycleState.STOPPING_PREP.compareTo(state) &lt;= <span class="hljs-number">0</span>
                &amp;&amp; LifecycleState.DESTROYED.compareTo(state) &gt;= <span class="hljs-number">0</span>) {
            <span class="hljs-comment">// Nothing to do. stop() was already called</span>
        } <span class="hljs-keyword">else</span> {
            s.stop();
            s.destroy();
        }
    } <span class="hljs-keyword">catch</span> (LifecycleException e) {
        log.error(<span class="hljs-string">"Catalina.stop"</span>, e);
    }
}</code></pre>

该方法首先移除关闭钩子,为什么要移除呢,因为他的任务已经完成了。然后设置useShutdownHook 为true。最后执行Server的stop方法,Server的stop方法基本和init方法和start方法一样,都是使用父类的模板方法,首先出发事件,然后调用stopInternal,该方法内部循环停止子容器,子容器递归停止,和我们之前的逻辑一致,不再赘述。destroy方法同理。

好了,我们已经看清了关闭钩子的逻辑,其实就是开辟一个守护线程交给虚拟机,然后虚拟机在某些异常情况(比如System.exit(0))前执行停止容器的逻辑。

好。我们回到start方法。

7. 回到 Catalina.start 方法

在设置好关闭钩子后,tomcat 的启动过程还没有启动完毕,接下来的逻辑式什么呢?

        if (useShutdownHook) {
            if (shutdownHook == null) {
                shutdownHook = new CatalinaShutdownHook();
            }
            Runtime.getRuntime().addShutdownHook(shutdownHook);
        <span class="hljs-comment">// If JULI is being used, disable JULI's shutdown hook since</span>
        <span class="hljs-comment">// shutdown hooks run in parallel and log messages may be lost</span>
        <span class="hljs-comment">// if JULI's hook completes before the CatalinaShutdownHook()</span>
        LogManager logManager = LogManager.getLogManager();
        <span class="hljs-keyword">if</span> (logManager <span class="hljs-keyword">instanceof</span> ClassLoaderLogManager) {
            ((ClassLoaderLogManager) logManager).setUseShutdownHook(
                    <span class="hljs-keyword">false</span>);
        }
    }

    <span class="hljs-keyword">if</span> (await) {
        await();
        stop();
    }</code></pre>

在设置完关闭钩子之后,会将 useShutdownHook 这个变量为false,然后执行 await 方法。然后执行stop方法,我们记得stop方法式关闭容器的方法,神经病啊,好不容易启动了,为什么又要关闭呢? 先不着急,我们还是看看 await 方法吧,该方法调用了Server.await 方法,我们来看看:

8. Catalian.await 方法实现

注意:该方法很长

    @Override
    public void await() {
        // Negative values - don't wait on port - tomcat is embedded or we just don't like ports
        if( port == -2 ) {
            // undocumented yet - for embedding apps that are around, alive.
            return;
        }
        if( port==-1 ) {
            try {
                awaitThread = Thread.currentThread();
                while(!stopAwait) {
                    try {
                        Thread.sleep( 10000 );
                    } catch( InterruptedException ex ) {
                        // continue and check the flag
                    }
                }
            } finally {
                awaitThread = null;
            }
            return;
        }
    <span class="hljs-comment">// Set up a server socket to wait on</span>
    <span class="hljs-keyword">try</span> {
        awaitSocket = <span class="hljs-keyword">new</span> ServerSocket(port, <span class="hljs-number">1</span>,
                InetAddress.getByName(address));
    } <span class="hljs-keyword">catch</span> (IOException e) {
        log.error(<span class="hljs-string">"StandardServer.await: create["</span> + address
                           + <span class="hljs-string">":"</span> + port
                           + <span class="hljs-string">"]: "</span>, e);
        <span class="hljs-keyword">return</span>;
    }

    <span class="hljs-keyword">try</span> {
        awaitThread = Thread.currentThread();

        <span class="hljs-comment">// Loop waiting for a connection and a valid command</span>
        <span class="hljs-keyword">while</span> (!stopAwait) {
            ServerSocket serverSocket = awaitSocket;
            <span class="hljs-keyword">if</span> (serverSocket == <span class="hljs-keyword">null</span>) {
                <span class="hljs-keyword">break</span>;
            }

            <span class="hljs-comment">// Wait for the next connection</span>
            Socket socket = <span class="hljs-keyword">null</span>;
            StringBuilder command = <span class="hljs-keyword">new</span> StringBuilder();
            <span class="hljs-keyword">try</span> {
                InputStream stream;
                <span class="hljs-keyword">try</span> {
                    socket = serverSocket.accept();
                    socket.setSoTimeout(<span class="hljs-number">10</span> * <span class="hljs-number">1000</span>);  <span class="hljs-comment">// Ten seconds</span>
                    stream = socket.getInputStream();
                } <span class="hljs-keyword">catch</span> (AccessControlException ace) {
                    log.warn(<span class="hljs-string">"StandardServer.accept security exception: "</span>
                            + ace.getMessage(), ace);
                    <span class="hljs-keyword">continue</span>;
                } <span class="hljs-keyword">catch</span> (IOException e) {
                    <span class="hljs-keyword">if</span> (stopAwait) {
                        <span class="hljs-comment">// Wait was aborted with socket.close()</span>
                        <span class="hljs-keyword">break</span>;
                    }
                    log.error(<span class="hljs-string">"StandardServer.await: accept: "</span>, e);
                    <span class="hljs-keyword">break</span>;
                }

                <span class="hljs-comment">// Read a set of characters from the socket</span>
                <span class="hljs-keyword">int</span> expected = <span class="hljs-number">1024</span>; <span class="hljs-comment">// Cut off to avoid DoS attack</span>
                <span class="hljs-keyword">while</span> (expected &lt; shutdown.length()) {
                    <span class="hljs-keyword">if</span> (random == <span class="hljs-keyword">null</span>)
                        random = <span class="hljs-keyword">new</span> Random();
                    expected += (random.nextInt() % <span class="hljs-number">1024</span>);
                }
                <span class="hljs-keyword">while</span> (expected &gt; <span class="hljs-number">0</span>) {
                    <span class="hljs-keyword">int</span> ch = -<span class="hljs-number">1</span>;
                    <span class="hljs-keyword">try</span> {
                        ch = stream.read();
                    } <span class="hljs-keyword">catch</span> (IOException e) {
                        log.warn(<span class="hljs-string">"StandardServer.await: read: "</span>, e);
                        ch = -<span class="hljs-number">1</span>;
                    }
                    <span class="hljs-keyword">if</span> (ch &lt; <span class="hljs-number">32</span>)  <span class="hljs-comment">// Control character or EOF terminates loop</span>
                        <span class="hljs-keyword">break</span>;
                    command.append((<span class="hljs-keyword">char</span>) ch);
                    expected--;
                }
            } <span class="hljs-keyword">finally</span> {
                <span class="hljs-comment">// Close the socket now that we are done with it</span>
                <span class="hljs-keyword">try</span> {
                    <span class="hljs-keyword">if</span> (socket != <span class="hljs-keyword">null</span>) {
                        socket.close();
                    }
                } <span class="hljs-keyword">catch</span> (IOException e) {
                    <span class="hljs-comment">// Ignore</span>
                }
            }

            <span class="hljs-comment">// Match against our command string</span>
            <span class="hljs-keyword">boolean</span> match = command.toString().equals(shutdown);
            <span class="hljs-keyword">if</span> (match) {
                log.info(sm.getString(<span class="hljs-string">"standardServer.shutdownViaPort"</span>));
                <span class="hljs-keyword">break</span>;
            } <span class="hljs-keyword">else</span>
                log.warn(<span class="hljs-string">"StandardServer.await: Invalid command '"</span>
                        + command.toString() + <span class="hljs-string">"' received"</span>);
        }
    } <span class="hljs-keyword">finally</span> {
        ServerSocket serverSocket = awaitSocket;
        awaitThread = <span class="hljs-keyword">null</span>;
        awaitSocket = <span class="hljs-keyword">null</span>;

        <span class="hljs-comment">// Close the server socket and return</span>
        <span class="hljs-keyword">if</span> (serverSocket != <span class="hljs-keyword">null</span>) {
            <span class="hljs-keyword">try</span> {
                serverSocket.close();
            } <span class="hljs-keyword">catch</span> (IOException e) {
                <span class="hljs-comment">// Ignore</span>
            }
        }
    }
}

我们看一下他的逻辑:首先创建一个socketServer 链接,然后循环等待消息。如果发过来的消息为字符串SHUTDOWN, 那么就break,停止循环,关闭socket。否则永不停歇。回到我们刚刚的疑问,await 方法后面执行 stop 方法,现在一看就合情合理了,只要不发出关闭命令,则不会执行stop方法,否则则继续执行关闭方法。

到现在,Tomcat 的整体启动过程我们已经了然于胸了,总结一下就是:
1. 初始化类加载器。
2. 初始化容器并注册到JMX后启动容器。
3. 设置关闭钩子。
4. 循环等待关闭命令。

等一下。好像缺了点什么??? Tomcat 启动后就只接受关闭命令,接受的http请求怎么处理,还要不要做一个合格的服务器了??? 别急,实际上,这个是主线程,负责生命周期等事情。处理Http请求的线程在初始化容器和启动容器的时候由子容器做了,这块的逻辑我们下次再讲。大家不要疑惑。

9. 我们知道了Tomcat 是怎么启动的,那么是怎么关闭的呢?

顺便说说关闭的逻辑:

shutdown.sh 脚本同样会调用 Bootstrap的main 方法,不同是传递 stop参数, 我们看看如果传递stop参数会怎么样:

ry {
            String command = "start";
            if (args.length > 0) {
                command = args[args.length - 1];
            }
            if (command.equals("startd")) {
                args[args.length - 1] = "start";
                daemon.load(args);
                daemon.start();
            }
            else if (command.equals("stopd")) {
                args[args.length - 1] = "stop";
                daemon.stop();
            }
            else if (command.equals("start")) {
                daemon.setAwait(true);
                daemon.load(args);
                daemon.start();
            } else if (command.equals("stop")) {
                daemon.stopServer(args);
            } else if (command.equals("configtest")) {
                daemon.load(args);
                if (null==daemon.getServer()) {
                    System.exit(1);
                }
                System.exit(0);
            } else {
                log.warn("Bootstrap: command \"" + command + "\" does not exist.");
            }
        } catch (Throwable t) {

可以看到调用的是 stopServer 方法,实际上就是 Catalina的stopServer 方法,我们看看该方法实现:

10. Catalina.stopServer 方法

 public void stopServer(String[] arguments) {
    <span class="hljs-keyword">if</span> (arguments != <span class="hljs-keyword">null</span>) {
        arguments(arguments);
    }

    Server s = getServer();
    <span class="hljs-keyword">if</span>( s == <span class="hljs-keyword">null</span> ) {
        <span class="hljs-comment">// Create and execute our Digester</span>
        Digester digester = createStopDigester();
        digester.setClassLoader(Thread.currentThread().getContextClassLoader());
        File file = configFile();
        FileInputStream fis = <span class="hljs-keyword">null</span>;
        <span class="hljs-keyword">try</span> {
            InputSource is =
                <span class="hljs-keyword">new</span> InputSource(file.toURI().toURL().toString());
            fis = <span class="hljs-keyword">new</span> FileInputStream(file);
            is.setByteStream(fis);
            digester.push(<span class="hljs-keyword">this</span>);
            digester.parse(is);
        } <span class="hljs-keyword">catch</span> (Exception e) {
            log.error(<span class="hljs-string">"Catalina.stop: "</span>, e);
            System.exit(<span class="hljs-number">1</span>);
        } <span class="hljs-keyword">finally</span> {
            <span class="hljs-keyword">if</span> (fis != <span class="hljs-keyword">null</span>) {
                <span class="hljs-keyword">try</span> {
                    fis.close();
                } <span class="hljs-keyword">catch</span> (IOException e) {
                    <span class="hljs-comment">// Ignore</span>
                }
            }
        }
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-comment">// Server object already present. Must be running as a service</span>
        <span class="hljs-keyword">try</span> {
            s.stop();
        } <span class="hljs-keyword">catch</span> (LifecycleException e) {
            log.error(<span class="hljs-string">"Catalina.stop: "</span>, e);
        }
        <span class="hljs-keyword">return</span>;
    }

    <span class="hljs-comment">// Stop the existing server</span>
    s = getServer();
    <span class="hljs-keyword">if</span> (s.getPort()&gt;<span class="hljs-number">0</span>) {
        Socket socket = <span class="hljs-keyword">null</span>;
        OutputStream stream = <span class="hljs-keyword">null</span>;
        <span class="hljs-keyword">try</span> {
            socket = <span class="hljs-keyword">new</span> Socket(s.getAddress(), s.getPort());
            stream = socket.getOutputStream();
            String shutdown = s.getShutdown();
            <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; shutdown.length(); i++) {
                stream.write(shutdown.charAt(i));
            }
            stream.flush();
        } <span class="hljs-keyword">catch</span> (ConnectException ce) {
            log.error(sm.getString(<span class="hljs-string">"catalina.stopServer.connectException"</span>,
                                   s.getAddress(),
                                   String.valueOf(s.getPort())));
            log.error(<span class="hljs-string">"Catalina.stop: "</span>, ce);
            System.exit(<span class="hljs-number">1</span>);
        } <span class="hljs-keyword">catch</span> (IOException e) {
            log.error(<span class="hljs-string">"Catalina.stop: "</span>, e);
            System.exit(<span class="hljs-number">1</span>);
        } <span class="hljs-keyword">finally</span> {
            <span class="hljs-keyword">if</span> (stream != <span class="hljs-keyword">null</span>) {
                <span class="hljs-keyword">try</span> {
                    stream.close();
                } <span class="hljs-keyword">catch</span> (IOException e) {
                    <span class="hljs-comment">// Ignore</span>
                }
            }
            <span class="hljs-keyword">if</span> (socket != <span class="hljs-keyword">null</span>) {
                <span class="hljs-keyword">try</span> {
                    socket.close();
                } <span class="hljs-keyword">catch</span> (IOException e) {
                    <span class="hljs-comment">// Ignore</span>
                }
            }
        }
    } <span class="hljs-keyword">else</span> {
        log.error(sm.getString(<span class="hljs-string">"catalina.stopServer"</span>));
        System.exit(<span class="hljs-number">1</span>);
    }
}

注意,该停止命令的虚拟机和启动的虚拟机不是一个虚拟机,因此,没有初始化 Server , 进入 IF 块,解析 server.xml 文件,获取文件中端口,用以创建Socket。然后像启动服务器发送 SHUTDOWN 命令,关闭启动服务器,启动服务器退出刚刚的循环,执行后面的 stop 方法,最后退出虚拟机,就是这么简单。

11. 总结

我们从整体上解析了Tomcat的启动和关闭过程,发现不是很难,为什么?因为我们之前已经分析过很多遍了,有些逻辑我们已经清除了,这次分析只是来扫尾。复杂的Tomcat的启动过程我们基本就分析完了。我们知道了启动和关闭都依赖Socket。只是我们惊奇的发现他的关闭竟然是如此实现。很牛逼。我原以为会像我们平时一样,直接kill。哈哈哈。

好吧。今天我们就到这里 ,tomcat 这座大山我们已经啃的差不多了,还剩一个 URL 请求过程和连接器,这两个部分是高度关联的,因此,楼主也会将他们放在一起分析。透过源码看真相。

连接器,等着我们来撕开你的衣服!!!!

good luck !!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值