? 在上一次 查看tomcat啟動(dòng)文件都干點(diǎn)啥 一文中,我們總結(jié)出, startup.bat文件的作用就是找到catalina.bat文件,然后把參數(shù)傳遞給它,在startup.bat中,調(diào)用catalina.bat的命令 call "%EXECUTABLE%" start %CMD_LINE_ARGS%,其中"%EXECUTABLE%"這個(gè)就是catalina.bat文件,這個(gè)命令至少向catalina.bat傳遞一個(gè)參數(shù)--start.
? ? ? 接下來(lái)看一下catalina.bat中的內(nèi)容,內(nèi)容很長(zhǎng):

1 @echo off 2 rem Licensed to the Apache Software Foundation (ASF) under one or more 3 rem contributor license agreements. See the NOTICE file distributed with 4 rem this work for additional information regarding copyright ownership. 5 rem The ASF licenses this file to You under the Apache License, Version 2.0 6 rem (the "License"); you may not use this file except in compliance with 7 rem the License. You may obtain a copy of the License at 8 rem 9 rem http://www.apache.org/licenses/LICENSE-2.0 10 rem 11 rem Unless required by applicable law or agreed to in writing, software 12 rem distributed under the License is distributed on an "AS IS" BASIS, 13 rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 rem See the License for the specific language governing permissions and 15 rem limitations under the License. 16 17 if "%OS%" == "Windows_NT" setlocal 18 rem --------------------------------------------------------------------------- 19 rem Start/Stop Script for the CATALINA Server 20 rem 21 rem Environment Variable Prerequisites 22 rem 23 rem CATALINA_HOME May point at your Catalina "build" directory. 24 rem 25 rem CATALINA_BASE (Optional) Base directory for resolving dynamic portions 26 rem of a Catalina installation. If not present, resolves to 27 rem the same directory that CATALINA_HOME points to. 28 rem 29 rem CATALINA_OPTS (Optional) Java runtime options used when the "start", 30 rem or "run" command is executed. 31 rem 32 rem CATALINA_TMPDIR (Optional) Directory path location of temporary directory 33 rem the JVM should use (java.io.tmpdir). Defaults to 34 rem %CATALINA_BASE%\temp. 35 rem 36 rem JAVA_HOME Must point at your Java Development Kit installation. 37 rem Required to run the with the "debug" argument. 38 rem 39 rem JRE_HOME Must point at your Java Runtime installation. 40 rem Defaults to JAVA_HOME if empty. 41 rem 42 rem JAVA_OPTS (Optional) Java runtime options used when the "start", 43 rem "stop", or "run" command is executed. 44 rem 45 rem JAVA_ENDORSED_DIRS (Optional) Lists of of semi-colon separated directories 46 rem containing some jars in order to allow replacement of APIs 47 rem created outside of the JCP (i.e. DOM and SAX from W3C). 48 rem It can also be used to update the XML parser implementation. 49 rem Defaults to $CATALINA_HOME/endorsed. 50 rem 51 rem JPDA_TRANSPORT (Optional) JPDA transport used when the "jpda start" 52 rem command is executed. The default is "dt_socket". 53 rem 54 rem JPDA_ADDRESS (Optional) Java runtime options used when the "jpda start" 55 rem command is executed. The default is 8000. 56 rem 57 rem JPDA_SUSPEND (Optional) Java runtime options used when the "jpda start" 58 rem command is executed. Specifies whether JVM should suspend 59 rem execution immediately after startup. Default is "n". 60 rem 61 rem JPDA_OPTS (Optional) Java runtime options used when the "jpda start" 62 rem command is executed. If used, JPDA_TRANSPORT, JPDA_ADDRESS, 63 rem and JPDA_SUSPEND are ignored. Thus, all required jpda 64 rem options MUST be specified. The default is: 65 rem 66 rem -agentlib:jdwp=transport=%JPDA_TRANSPORT%, 67 rem address=%JPDA_ADDRESS%,server=y,suspend=%JPDA_SUSPEND% 68 rem 69 rem LOGGING_CONFIG (Optional) Override Tomcat's logging config file 70 rem Example (all one line) 71 rem set LOGGING_CONFIG="-Djava.util.logging.config.file=%CATALINA_BASE%\conf\logging.properties" 72 rem 73 rem LOGGING_MANAGER (Optional) Override Tomcat's logging manager 74 rem Example (all one line) 75 rem set LOGGING_MANAGER="-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager" 76 rem 77 rem TITLE (Optional) Specify the title of Tomcat window. The default 78 rem TITLE is Tomcat if it's not specified. 79 rem Example (all one line) 80 rem set TITLE=Tomcat.Cluster#1.Server#1 [%DATE% %TIME%] 81 rem 82 rem 83 rem 84 rem $Id: catalina.bat 1040546 2010-11-30 14:47:34Z markt $ 85 rem --------------------------------------------------------------------------- 86 87 rem Suppress Terminate batch job on CTRL+C 88 if not "" %1 "" == "" run "" goto mainEntry 89 if ""%TEMP%"" == """" goto mainEntry 90 if exist "%TEMP%\%~nx0.run" goto mainEntry 91 echo Y>"%TEMP%\%~nx0.run" 92 if not exist "%TEMP%\%~nx0.run" goto mainEntry 93 echo Y>"%TEMP%\%~nx0.Y" 94 call "%~f0" %* <"%TEMP%\%~nx0.Y" 95 rem Use provided errorlevel 96 set RETVAL=% ERRORLEVEL % 97 del /Q "%TEMP%\%~nx0.Y" >NUL 2>&1 98 exit / B %RETVAL% 99 :mainEntry 100 del /Q "%TEMP%\%~nx0.run" >NUL 2>&1 101 102 rem Guess CATALINA_HOME if not defined 103 set "CURRENT_DIR=%cd%" 104 if not "%CATALINA_HOME%" == "" goto gotHome 105 set "CATALINA_HOME=%CURRENT_DIR%" 106 if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome 107 cd .. 108 set "CATALINA_HOME=%cd%" 109 cd "%CURRENT_DIR%" 110 :gotHome 111 if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome 112 echo The CATALINA_HOME environment variable is not defined correctly 113 echo This environment variable is needed to run this program 114 goto end 115 :okHome 116 117 rem Ensure that any user defined CLASSPATH variables are not used on startup, 118 rem but allow them to be specified in setenv.bat, in rare case when it is needed. 119 set CLASSPATH= 120 121 rem Get standard environment variables 122 if "%CATALINA_BASE%" == "" goto gotSetenvHome 123 if exist "%CATALINA_BASE%\bin\setenv.bat" call "%CATALINA_BASE%\bin\setenv.bat" 124 goto gotSetenvBase 125 :gotSetenvHome 126 if exist "%CATALINA_HOME%\bin\setenv.bat" call "%CATALINA_HOME%\bin\setenv.bat" 127 :gotSetenvBase 128 129 rem Get standard Java environment variables 130 if exist "%CATALINA_HOME%\bin\setclasspath.bat" goto okSetclasspath 131 echo Cannot find "%CATALINA_HOME%\bin\setclasspath.bat" 132 echo This file is needed to run this program 133 goto end 134 :okSetclasspath 135 set "BASEDIR=%CATALINA_HOME%" 136 call "%CATALINA_HOME%\bin\setclasspath.bat" %1 137 if errorlevel 1 goto end 138 139 rem Add on extra jar file to CLASSPATH 140 rem Note that there are no quotes as we do not want to introduce random 141 rem quotes into the CLASSPATH 142 if "%CLASSPATH%" == "" goto emptyClasspath 143 set "CLASSPATH=%CLASSPATH%;" 144 :emptyClasspath 145 set "CLASSPATH=%CLASSPATH%%CATALINA_HOME%\bin\bootstrap.jar" 146 147 if not "%CATALINA_BASE%" == "" goto gotBase 148 set "CATALINA_BASE=%CATALINA_HOME%" 149 :gotBase 150 151 if not "%CATALINA_TMPDIR%" == "" goto gotTmpdir 152 set "CATALINA_TMPDIR=%CATALINA_BASE%\temp" 153 :gotTmpdir 154 155 rem Add tomcat-juli.jar to classpath 156 rem tomcat-juli.jar can be over-ridden per instance 157 if not exist "%CATALINA_BASE%\bin\tomcat-juli.jar" goto juliClasspathHome 158 set "CLASSPATH=%CLASSPATH%;%CATALINA_BASE%\bin\tomcat-juli.jar" 159 goto juliClasspathDone 160 :juliClasspathHome 161 set "CLASSPATH=%CLASSPATH%;%CATALINA_HOME%\bin\tomcat-juli.jar" 162 :juliClasspathDone 163 164 if not "%LOGGING_CONFIG%" == "" goto noJuliConfig 165 set LOGGING_CONFIG= -Dnop 166 if not exist "%CATALINA_BASE%\conf\logging.properties" goto noJuliConfig 167 set LOGGING_CONFIG=-Djava.util.logging.config.file="%CATALINA_BASE%\conf\logging.properties" 168 :noJuliConfig 169 set JAVA_OPTS= %JAVA_OPTS% %LOGGING_CONFIG% 170 171 if not "%LOGGING_MANAGER%" == "" goto noJuliManager 172 set LOGGING_MANAGER=-Djava.util.logging.manager=org.apache.juli. ClassLoaderLogManager 173 :noJuliManager 174 set JAVA_OPTS= %JAVA_OPTS% %LOGGING_MANAGER% 175 176 rem ----- Execute The Requested Command --------------------------------------- 177 178 echo Using CATALINA_BASE: "%CATALINA_BASE%" 179 echo Using CATALINA_HOME: "%CATALINA_HOME%" 180 echo Using CATALINA_TMPDIR: "%CATALINA_TMPDIR%" 181 if "" %1 "" == "" debug "" goto use_jdk 182 echo Using JRE_HOME: "%JRE_HOME%" 183 goto java_dir_displayed 184 :use_jdk 185 echo Using JAVA_HOME: "%JAVA_HOME%" 186 :java_dir_displayed 187 echo Using CLASSPATH: "%CLASSPATH%" 188 189 set _EXECJAVA= %_RUNJAVA% 190 set MAINCLASS=org.apache.catalina.startup. Bootstrap 191 set ACTION= start 192 set SECURITY_POLICY_FILE= 193 set DEBUG_OPTS= 194 set JPDA= 195 196 if not "" %1 "" == ""jpda"" goto noJpda 197 set JPDA= jpda 198 if not "%JPDA_TRANSPORT%" == "" goto gotJpdaTransport 199 set JPDA_TRANSPORT= dt_socket 200 :gotJpdaTransport 201 if not "%JPDA_ADDRESS%" == "" goto gotJpdaAddress 202 set JPDA_ADDRESS=8000 203 :gotJpdaAddress 204 if not "%JPDA_SUSPEND%" == "" goto gotJpdaSuspend 205 set JPDA_SUSPEND= n 206 :gotJpdaSuspend 207 if not "%JPDA_OPTS%" == "" goto gotJpdaOpts 208 set JPDA_OPTS=-agentlib :jdwp =transport=%JPDA_TRANSPORT%,address=%JPDA_ADDRESS%,server=y,suspend= %JPDA_SUSPEND% 209 :gotJpdaOpts 210 shift 211 :noJpda 212 213 if "" %1 "" == "" debug "" goto doDebug 214 if "" %1 "" == "" run "" goto doRun 215 if "" %1 "" == "" start "" goto doStart 216 if "" %1 "" == ""stop"" goto doStop 217 if "" %1 "" == ""version"" goto doVersion 218 219 echo Usage: catalina ( commands ... ) 220 echo commands: 221 echo debug Start Catalina in a debugger 222 echo debug -security Debug Catalina with a security manager 223 echo jpda start Start Catalina under JPDA debugger 224 echo run Start Catalina in the current window 225 echo run -security Start in the current window with security manager 226 echo start Start Catalina in a separate window 227 echo start -security Start in a separate window with security manager 228 echo stop Stop Catalina 229 echo version What version of tomcat are you running? 230 goto end 231 232 :doDebug 233 shift 234 set _EXECJAVA= %_RUNJDB% 235 set DEBUG_OPTS=-sourcepath "%CATALINA_HOME%\..\..\java" 236 if not "" %1 "" == ""-security"" goto execCmd 237 shift 238 echo Using Security Manager 239 set "SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy" 240 goto execCmd 241 242 :doRun 243 shift 244 if not "" %1 "" == ""-security"" goto execCmd 245 shift 246 echo Using Security Manager 247 set "SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy" 248 goto execCmd 249 250 :doStart 251 shift 252 if not "%OS%" == "Windows_NT" goto noTitle 253 if "%TITLE%" == "" set TITLE= Tomcat 254 set _EXECJAVA= start "%TITLE%" %_RUNJAVA% 255 goto gotTitle 256 :noTitle 257 set _EXECJAVA= start %_RUNJAVA% 258 :gotTitle 259 if not "" %1 "" == ""-security"" goto execCmd 260 shift 261 echo Using Security Manager 262 set "SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy" 263 goto execCmd 264 265 :doStop 266 shift 267 set ACTION= stop 268 set CATALINA_OPTS= 269 goto execCmd 270 271 :doVersion 272 %_EXECJAVA% -classpath "%CATALINA_HOME%\lib\catalina.jar" org.apache.catalina.util. ServerInfo 273 goto end 274 275 276 :execCmd 277 rem Get remaining unshifted command line arguments and save them in the 278 set CMD_LINE_ARGS= 279 :setArgs 280 if "" %1 ""=="""" goto doneSetArgs 281 set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1 282 shift 283 goto setArgs 284 :doneSetArgs 285 286 rem Execute Java with the applicable properties 287 if not "%JPDA%" == "" goto doJpda 288 if not "%SECURITY_POLICY_FILE%" == "" goto doSecurity 289 %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION% 290 goto end 291 :doSecurity 292 %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Djava.security.manager -Djava.security.policy=="%SECURITY_POLICY_FILE%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION% 293 goto end 294 :doJpda 295 if not "%SECURITY_POLICY_FILE%" == "" goto doSecurityJpda 296 %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %JPDA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION% 297 goto end 298 :doSecurityJpda 299 %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %JPDA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Djava.security.manager -Djava.security.policy=="%SECURITY_POLICY_FILE%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION% 300 goto end 301 302 :end
在第1行,和第17行中的內(nèi)容已經(jīng)在前一章中做出說(shuō)明,在此處不再敖述,我對(duì)于18-85行的這段注釋比較感興趣:
1 rem --------------------------------------------------------------------------- 2 rem Start/Stop Script for the CATALINA Server 3 rem 4 rem Environment Variable Prerequisites 5 rem 6 rem CATALINA_HOME May point at your Catalina "build" directory. 7 rem 8 rem CATALINA_BASE (Optional) Base directory for resolving dynamic portions 9 rem of a Catalina installation. If not present, resolves to 10 rem the same directory that CATALINA_HOME points to. 11 rem 12 rem CATALINA_OPTS (Optional) Java runtime options used when the "start", 13 rem or "run" command is executed. 14 rem 15 rem CATALINA_TMPDIR (Optional) Directory path location of temporary directory 16 rem the JVM should use (java.io.tmpdir). Defaults to 17 rem %CATALINA_BASE%\temp. 18 rem 19 rem JAVA_HOME Must point at your Java Development Kit installation. 20 rem Required to run the with the "debug" argument. 21 rem 22 rem JRE_HOME Must point at your Java Runtime installation. 23 rem Defaults to JAVA_HOME if empty. 24 rem 25 rem JAVA_OPTS (Optional) Java runtime options used when the "start", 26 rem "stop", or "run" command is executed. 27 rem 28 rem JAVA_ENDORSED_DIRS (Optional) Lists of of semi-colon separated directories 29 rem containing some jars in order to allow replacement of APIs 30 rem created outside of the JCP (i.e. DOM and SAX from W3C). 31 rem It can also be used to update the XML parser implementation. 32 rem Defaults to $CATALINA_HOME/endorsed. 33 rem 34 rem JPDA_TRANSPORT (Optional) JPDA transport used when the "jpda start" 35 rem command is executed. The default is "dt_socket". 36 rem 37 rem JPDA_ADDRESS (Optional) Java runtime options used when the "jpda start" 38 rem command is executed. The default is 8000. 39 rem 40 rem JPDA_SUSPEND (Optional) Java runtime options used when the "jpda start" 41 rem command is executed. Specifies whether JVM should suspend 42 rem execution immediately after startup. Default is "n". 43 rem 44 rem JPDA_OPTS (Optional) Java runtime options used when the "jpda start" 45 rem command is executed. If used, JPDA_TRANSPORT, JPDA_ADDRESS, 46 rem and JPDA_SUSPEND are ignored. Thus, all required jpda 47 rem options MUST be specified. The default is: 48 rem 49 rem -agentlib:jdwp=transport=%JPDA_TRANSPORT%, 50 rem address=%JPDA_ADDRESS%,server=y,suspend=%JPDA_SUSPEND% 51 rem 52 rem LOGGING_CONFIG (Optional) Override Tomcat's logging config file 53 rem Example (all one line) 54 rem set LOGGING_CONFIG="-Djava.util.logging.config.file=%CATALINA_BASE%\conf\logging.properties" 55 rem 56 rem LOGGING_MANAGER (Optional) Override Tomcat's logging manager 57 rem Example (all one line) 58 rem set LOGGING_MANAGER="-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager" 59 rem 60 rem TITLE (Optional) Specify the title of Tomcat window. The default 61 rem TITLE is Tomcat if it's not specified. 62 rem Example (all one line) 63 rem set TITLE=Tomcat.Cluster#1.Server#1 [%DATE% %TIME%] 64 rem 65 rem 66 rem 67 rem $Id: catalina.bat 1040546 2010-11-30 14:47:34Z markt $ 68 rem ---------------------------------------------------------------------------
這段的內(nèi)容就是說(shuō)明一下在啟動(dòng)和停止CATALINA server時(shí)候需要的一下先決條件,CATALINA_HOME--看到這個(gè)大家可能會(huì)有點(diǎn)疑問(wèn),如果在操作系統(tǒng)上沒(méi)有設(shè)置CATALINA_HOME變量的時(shí)候,那么這個(gè)變量應(yīng)該是不存在的丫,是怎么回事呢?是不是?下面我們還是用測(cè)試來(lái)說(shuō)明問(wèn)題:我在F:\apache-tomcat-7.0.8\bin目錄下創(chuàng)建一個(gè)test.bat文件,文件內(nèi)容如下:
@echo off set CURRENT_DIR=% cd % test2 .bat
? ?意思很簡(jiǎn)單,只是將%cd%變量的值賦給CURRENT_DIR變量,然后調(diào)用test2.bat文件,test2.bat文件的內(nèi)容如下:
echo
%CURRENT_DIR%
? 只是簡(jiǎn)單的輸出%CURRENT_DIR%變量,讓我們先運(yùn)行test.bat文件,查看%CURRENT_DIR%變量是否能夠正確輸出:
? ? ? ?結(jié)果正確顯示了,但是如果我們直接運(yùn)行test2.bat文件會(huì)有什么結(jié)果呢?
? ? ? 結(jié)果顯示不正常,這個(gè)測(cè)試就說(shuō)明由test.bat調(diào)用test2.bat文件時(shí)候,test.bat中定義的變量在test2.bat中可見,就是CURRENT_DIR變量的生命周期范圍并不是僅限于本文件,也能加深對(duì)于setlocal方法的理解。回到catalina.bat本身,也許我們本身沒(méi)有設(shè)置CATALINA_HOME環(huán)境變量的習(xí)慣,但是回想一下上一節(jié),在startup.bat中說(shuō)到,如果沒(méi)有設(shè)置CATALINA_HOME變量,startup.bat內(nèi)會(huì)給CATALINA_HOME變量賦值,然后在catalina.bat中依然能夠訪問(wèn)此變量。
? ? ?這段注釋說(shuō)完之后,看一下88行:?
if not "" %1 "" == "" run "" goto mainEntry
如果接收到的第一個(gè)參數(shù)是run那么到:mainEntry節(jié)點(diǎn),事實(shí)是我們從startup.bat調(diào)用的時(shí)候傳遞的第一個(gè)參數(shù)無(wú)疑是start,所以應(yīng)該順序執(zhí)行到第89行,這里可能有人會(huì)有疑問(wèn),那什么時(shí)候第一個(gè)參數(shù)才是run呢?事情是這樣的,因?yàn)椴⒉皇撬腥硕际歉覀円粯又苯邮褂胹tartup.bat文件啟動(dòng),因?yàn)閟tartup.bat文件也只不過(guò)就是找到catalina.bat文件,然后照樣傳遞參數(shù),其實(shí)有經(jīng)驗(yàn)的人大可直接使用catalina.bat文件來(lái)啟動(dòng)tomcat。這就是第一個(gè)參數(shù)為run的產(chǎn)生情況。接下來(lái)我們順序執(zhí)行到第89行。
? ? 看一下89行的內(nèi)容:
if ""%TEMP%"" == """" goto mainEntry
?如果TEMP變量為空,那么到mainEntry節(jié)點(diǎn),這個(gè)時(shí)候我們就需要看看我們到底有沒(méi)有這個(gè)TEMP變量,同樣弄個(gè)小測(cè)試,寫一個(gè)小的測(cè)試test.bat文件,文件內(nèi)容如下:
@echo off echo %TEMP%
查看執(zhí)行結(jié)果:
?
? ? ? 記得在上一節(jié)中說(shuō)過(guò)%TEMP%這個(gè)變量是從環(huán)境變量中讀取的,所以也可以去環(huán)境變量中查看是不是有此值,來(lái)確定TEMP變量是不是存在,一問(wèn)在startup.bat和catalina.bat并沒(méi)有設(shè)置TEMP變量。查看環(huán)境變量:
? ? ?因?yàn)門EMP存在,所以程序還需要順序執(zhí)行到90行,第90行的內(nèi)容如下:? ?
if exist "%TEMP%\%~nx0.run" goto mainEntry
這句話至少看起來(lái)有點(diǎn)蒙圈,尤其是\%~nx0.run這個(gè)東西,反正我第一次看見的時(shí)候我就想問(wèn)問(wèn),這是毛啊,~nx0,下面看一下網(wǎng)上對(duì)于%~nx0的解釋:
%~nx0 contains the name of the running batch file (without the
path
)
意思就是代表執(zhí)行命令的文件的名字,我們來(lái)用實(shí)驗(yàn)證明一下,同樣還是修改那個(gè)test.bat文件吧。;-)
@echo off echo "%TEMP%\%~nx0.run"
如果按照上面的解釋,那么輸出的信息應(yīng)該是C:\Users\Think\AppData\Local\Temp\test.bat.run,下面看一下運(yùn)行結(jié)果:
咦事實(shí)證明說(shuō)法正確,但是這個(gè)文件是不是存在呢,我們?nèi)EMP目錄下看一下,遺憾的是在C:\Users\Think\AppData\Local\Temp目錄沒(méi)有找到這個(gè)文件,所以還得順序執(zhí)行到第91行,91行的內(nèi)容是:
echo
Y>"%TEMP%\%~nx0.run"
這個(gè)看起來(lái)很簡(jiǎn)單,既然不存在這個(gè)文件,那么我就自己創(chuàng)建一個(gè),同時(shí)寫入Y。也許你不信,所以我還是拿出個(gè)例子吧,還是test.bat呦:
@echo off echo Y>"%TEMP%\%~nx0.run"
在C:\Users\Think\AppData\Local\Temp目錄下生成了test.bat.run文件,文件的內(nèi)容果然為Y。至于生成的文件有何意義,以后再說(shuō)。到現(xiàn)在位置我突然感慨,我很喜歡TOMCAT,它做了什么我都能知道,在接下來(lái)的一段時(shí)間內(nèi),我想把我看TOMCAT源代碼的感受也下下來(lái)。也跟大家討論一下TOMCAT的工作原理。有點(diǎn)遠(yuǎn),扯回來(lái),下面看一下92行的內(nèi)容:
if not exist "%TEMP%\%~nx0.run" goto mainEntry
這個(gè)一眼就看明白了,再次判斷%~nx0.run文件是否存在,如果還是不存在,那么直接到mainEntry節(jié)點(diǎn),由于我們此時(shí)此文件已經(jīng)創(chuàng)建成功,那么順序執(zhí)行到第93行。
93行的內(nèi)容為:
echo
Y>"%TEMP%\%~nx0.Y"
這個(gè)同91行命令,不再?gòu)?qiáng)調(diào)。順序執(zhí)行到92行。
92行的內(nèi)容為:
call
"%~f0" %* <"%TEMP%\%~nx0.Y"
看到之后感覺依然是蒙圈,這里面有兩個(gè)點(diǎn)需要大家掌握:%~f0, %* 知道這兩組符號(hào)是什么意思,就解決了。
%~f0:表示運(yùn)行的文件的全路徑,假如我在test.bat中如此寫:
@echo off @echo %%~f0 is %~f0
那么執(zhí)行結(jié)果為:
? ? ?OK。
%*:在batch file中,每一個(gè)命令的參數(shù)都以%1,%2,%3 .....的形式展現(xiàn),我們也可以使用%來(lái)代替所有的參數(shù),下面看修改萬(wàn)能測(cè)試文件test.bat中的內(nèi)容如下:
@echo off echo First argument: [ %1 ] echo Second argument: [ %2 ] echo Third argument: [ %3 ] echo Fourth argument: [ %4 ] echo Fifth argument: [ %4 ] echo Entire command line: [%*]
查看運(yùn)行結(jié)果:
意思就是將在catalina.bat文件中自己調(diào)用自己,傳遞參數(shù)Y,下面看一下測(cè)試,將test.bat中的內(nèi)容改為:
@echo off call "%~f0" %* <"%TEMP%\%~nx0.Y"
查看運(yùn)行結(jié)果,在程序運(yùn)行了一段時(shí)間以后,得出如下結(jié)論:
很奇怪,奇怪亮點(diǎn),為什么運(yùn)行的時(shí)候會(huì)有停頓,第二,為什么會(huì)產(chǎn)生這個(gè)結(jié)果。下面解決這兩個(gè)困惑,我覺得程序在運(yùn)行的時(shí)候肯定是在后臺(tái)運(yùn)行什么操作了,所以我將test.bat中的內(nèi)容改了一下: ?
call
"%~f0" %* <"%TEMP%\%~nx0.Y"
然后再次運(yùn)行,得到結(jié)果:
原來(lái)程序在輸出最終結(jié)果之前一直到在調(diào)用自己,所以會(huì)有一個(gè)停頓的感覺。
第二:為什么會(huì)產(chǎn)生這個(gè)結(jié)果:
下面看第96行的內(nèi)容:
set RETVAL=% ERRORLEVEL %
在前面的的內(nèi)容中可能給大家一種誤解,所以在看到這句話的時(shí)候,不知道是不是也有人跟我似的直接去環(huán)境變量中找ERRORLEVEL的值,找不到之后覺得我在忽悠大家,下面我跟大家說(shuō)說(shuō)這個(gè)ERRORLEVEL。不知道大家是不是了解在Linux中的$?這個(gè)結(jié)果返回值,其實(shí)ERRORLEVEL和$?差不多,都是用來(lái)表示上次執(zhí)行結(jié)果的,如果返回0說(shuō)明執(zhí)行正確,如果不是0說(shuō)明執(zhí)行失敗。例如在test.bat中的內(nèi)容:
call % ERRORLEVEL %
執(zhí)行結(jié)果:
下面看97行的內(nèi)容:
del
/Q "%TEMP%\%~nx0.Y" >NUL 2>&1
這里面有/Q, >NUL, 2>&1需要跟大家解釋一下:
/Q: 跟在del后面表示不需要交互式的刪除。安靜模式的意思。如在test.bat中的內(nèi)容如下:
del
/Q "%TEMP%\%~nx0.Y" >NUL 2>&1
然后運(yùn)行結(jié)果為:
此時(shí)文件系統(tǒng)中的文件確實(shí)已經(jīng)被刪除,只是在刪除的過(guò)程中沒(méi)有顯示刪除的過(guò)程,下面我們重新創(chuàng)建此文件,然后把/Q標(biāo)記去掉以后在嘗試一次:
>NUL 就是將輸出輸出到NUL中,這樣有錯(cuò)誤的情況下你什么都拿不到。
2>&1:2是值錯(cuò)誤輸出,&1是標(biāo)準(zhǔn)輸出,意思就是將錯(cuò)誤輸出重定向到標(biāo)準(zhǔn)輸出中
?>NUL 2>&1的意思就是將錯(cuò)誤輸出重定向到標(biāo)準(zhǔn)輸出,最后在重定向到NUL中,這樣出現(xiàn)錯(cuò)誤,你從表面上不會(huì)看出來(lái)。如果將test.bat中的刪除操作執(zhí)行多次,
@echo off del /Q "%TEMP%\%~nx0.Y" >NUL 2>&1
看結(jié)果:
也不會(huì)顯示異常,如果將>NUL 2>&1刪除以后,再次執(zhí)行:
@echo off del /Q "%TEMP%\%~nx0.Y"
結(jié)果就會(huì)顯示出異常:
下面看第98行的內(nèi)容:
exit
/B %RETVAL%
? 下面的mainEntry和gotHome節(jié)點(diǎn)的信息同前一節(jié)剛開始的內(nèi)容一樣,所有就不再說(shuō)明,如果對(duì)此有什么疑問(wèn),請(qǐng)查看 查看tomcat啟動(dòng)文件都干點(diǎn)啥 一節(jié)。在接下來(lái)的部分中我想把115-137行的內(nèi)容放在一起說(shuō)明,因?yàn)樗麄兎譃閮刹糠郑謩e引入setenv.bat和setclasspath.bat并執(zhí)行,
:okHome rem Ensure that any user defined CLASSPATH variables are not used on startup, rem but allow them to be specified in setenv.bat, in rare case when it is needed. set CLASSPATH= rem Get standard environment variables if "%CATALINA_BASE%" == "" goto gotSetenvHome if exist "%CATALINA_BASE%\bin\setenv.bat" call "%CATALINA_BASE%\bin\setenv.bat" goto gotSetenvBase :gotSetenvHome if exist "%CATALINA_HOME%\bin\setenv.bat" call "%CATALINA_HOME%\bin\setenv.bat" :gotSetenvBase rem Get standard Java environment variables if exist "%CATALINA_HOME%\bin\setclasspath.bat" goto okSetclasspath echo Cannot find "%CATALINA_HOME%\bin\setclasspath.bat" echo This file is needed to run this program goto end :okSetclasspath set "BASEDIR=%CATALINA_HOME%" call "%CATALINA_HOME%\bin\setclasspath.bat" %1 if errorlevel 1 goto end
這部分的操作就是設(shè)置環(huán)境變量,由于在tomcat7.0.8版本中不存在setenv.bat所以就不說(shuō)了,setclasspath.bat這個(gè)腳本很重要,瀏覽一下其中的內(nèi)容:

@echo off rem Licensed to the Apache Software Foundation (ASF) under one or more rem contributor license agreements. See the NOTICE file distributed with rem this work for additional information regarding copyright ownership. rem The ASF licenses this file to You under the Apache License, Version 2.0 rem (the "License"); you may not use this file except in compliance with rem the License. You may obtain a copy of the License at rem rem http://www.apache.org/licenses/LICENSE-2.0 rem rem Unless required by applicable law or agreed to in writing, software rem distributed under the License is distributed on an "AS IS" BASIS, rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. rem See the License for the specific language governing permissions and rem limitations under the License. rem --------------------------------------------------------------------------- rem Set JAVA_HOME or JRE_HOME if not already set, ensure any provided settings rem are valid and consistent with the selected start-up options and set up the rem endorsed directory. rem rem $Id: setclasspath.bat 964208 2010-07-14 21:24:45Z markt $ rem --------------------------------------------------------------------------- rem Make sure prerequisite environment variables are set if not "%JAVA_HOME%" == "" goto gotJdkHome if not "%JRE_HOME%" == "" goto gotJreHome echo Neither the JAVA_HOME nor the JRE_HOME environment variable is defined echo At least one of these environment variable is needed to run this program goto exit :gotJreHome if not exist "%JRE_HOME%\bin\java.exe" goto noJavaHome if not exist "%JRE_HOME%\bin\javaw.exe" goto noJavaHome if not "" %1 "" == "" debug "" goto okJavaHome echo JAVA_HOME should point to a JDK in order to run in debug mode . goto exit :gotJdkHome if not exist "%JAVA_HOME%\bin\java.exe" goto noJavaHome if not exist "%JAVA_HOME%\bin\javaw.exe" goto noJavaHome if not exist "%JAVA_HOME%\bin\jdb.exe" goto noJavaHome if not exist "%JAVA_HOME%\bin\javac.exe" goto noJavaHome if not "%JRE_HOME%" == "" goto okJavaHome set "JRE_HOME=%JAVA_HOME%" goto okJavaHome :noJavaHome echo The JAVA_HOME environment variable is not defined correctly echo This environment variable is needed to run this program echo NB: JAVA_HOME should point to a JDK not a JRE goto exit :okJavaHome if not "%BASEDIR%" == "" goto gotBasedir echo The BASEDIR environment variable is not defined echo This environment variable is needed to run this program goto exit :gotBasedir if exist "%BASEDIR%\bin\setclasspath.bat" goto okBasedir echo The BASEDIR environment variable is not defined correctly echo This environment variable is needed to run this program goto exit :okBasedir rem Don't override the endorsed dir if the user has set it previously if not "%JAVA_ENDORSED_DIRS%" == "" goto gotEndorseddir rem Set the default -Djava.endorsed.dirs argument set "JAVA_ENDORSED_DIRS=%BASEDIR%\endorsed" :gotEndorseddir rem Set standard command for invoking Java. rem Note that NT requires a window name argument when using start. rem Also note the quoting as JAVA_HOME may contain spaces. set _RUNJAVA="%JRE_HOME%\bin\java" set _RUNJDB="%JAVA_HOME%\bin\jdb" goto end :exit exit /b 1 :end exit /b 0
其中就是關(guān)于JAVA環(huán)境的一些校驗(yàn)和變量的設(shè)置,重要性不言而喻,所以如果執(zhí)行本步操作失敗的情況下,程序?qū)⑼顺鰣?zhí)行。
接下來(lái)是設(shè)置CLASSPATH的內(nèi)容,看過(guò)前面的說(shuō)明以后,對(duì)于下面的內(nèi)容應(yīng)該很容易就能看懂:
rem Add on extra jar file to CLASSPATH rem Note that there are no quotes as we do not want to introduce random rem quotes into the CLASSPATH if "%CLASSPATH%" == "" goto emptyClasspath set "CLASSPATH=%CLASSPATH%;" :emptyClasspath set "CLASSPATH=%CLASSPATH%%CATALINA_HOME%\bin\bootstrap.jar" if not "%CATALINA_BASE%" == "" goto gotBase set "CATALINA_BASE=%CATALINA_HOME%" :gotBase if not "%CATALINA_TMPDIR%" == "" goto gotTmpdir set "CATALINA_TMPDIR=%CATALINA_BASE%\temp" :gotTmpdir rem Add tomcat-juli.jar to classpath rem tomcat-juli.jar can be over-ridden per instance if not exist "%CATALINA_BASE%\bin\tomcat-juli.jar" goto juliClasspathHome set "CLASSPATH=%CLASSPATH%;%CATALINA_BASE%\bin\tomcat-juli.jar" goto juliClasspathDone :juliClasspathHome set "CLASSPATH=%CLASSPATH%;%CATALINA_HOME%\bin\tomcat-juli.jar" :juliClasspathDone
將tomcat-juli.jar和bootstrap.jar的全路徑追加到CLASSPATH中,究竟這兩個(gè)jar包是做什么的,不是本文的范疇,只說(shuō)明這兩個(gè)jar包需要在CLASSPATH中體現(xiàn)。
接下來(lái)是關(guān)于Log選項(xiàng)的問(wèn)題:

if not "%LOGGING_CONFIG%" == "" goto noJuliConfig set LOGGING_CONFIG= -Dnop if not exist "%CATALINA_BASE%\conf\logging.properties" goto noJuliConfig set LOGGING_CONFIG=-Djava.util.logging.config.file="%CATALINA_BASE%\conf\logging.properties" :noJuliConfig set JAVA_OPTS= %JAVA_OPTS% %LOGGING_CONFIG% if not "%LOGGING_MANAGER%" == "" goto noJuliManager set LOGGING_MANAGER=-Djava.util.logging.manager=org.apache.juli. ClassLoaderLogManager :noJuliManager set JAVA_OPTS=%JAVA_OPTS% %LOGGING_MANAGER%
內(nèi)容很簡(jiǎn)單,一看就明白,所以也不多說(shuō)了。
在前面準(zhǔn)備了這么久,接下來(lái)終于到執(zhí)行的時(shí)候了。下面看一下這段腳本:

rem ----- Execute The Requested Command --------------------------------------- echo Using CATALINA_BASE: "%CATALINA_BASE%" echo Using CATALINA_HOME: "%CATALINA_HOME%" echo Using CATALINA_TMPDIR: "%CATALINA_TMPDIR%" if "" %1 "" == "" debug "" goto use_jdk echo Using JRE_HOME: "%JRE_HOME%" goto java_dir_displayed :use_jdk echo Using JAVA_HOME: "%JAVA_HOME%" :java_dir_displayed echo Using CLASSPATH: "%CLASSPATH%" set _EXECJAVA= %_RUNJAVA% set MAINCLASS=org.apache.catalina.startup. Bootstrap set ACTION= start set SECURITY_POLICY_FILE= set DEBUG_OPTS= set JPDA= if not "" %1 "" == ""jpda"" goto noJpda set JPDA= jpda if not "%JPDA_TRANSPORT%" == "" goto gotJpdaTransport set JPDA_TRANSPORT= dt_socket :gotJpdaTransport if not "%JPDA_ADDRESS%" == "" goto gotJpdaAddress set JPDA_ADDRESS=8000 :gotJpdaAddress if not "%JPDA_SUSPEND%" == "" goto gotJpdaSuspend set JPDA_SUSPEND= n :gotJpdaSuspend if not "%JPDA_OPTS%" == "" goto gotJpdaOpts set JPDA_OPTS=-agentlib :jdwp =transport=%JPDA_TRANSPORT%,address=%JPDA_ADDRESS%,server=y,suspend= %JPDA_SUSPEND% :gotJpdaOpts shift :noJpda if "" %1 "" == "" debug "" goto doDebug if "" %1 "" == "" run "" goto doRun if "" %1 "" == "" start "" goto doStart if "" %1 "" == ""stop"" goto doStop if "" %1 "" == ""version"" goto doVersion echo Usage: catalina ( commands ... ) echo commands: echo debug Start Catalina in a debugger echo debug -security Debug Catalina with a security manager echo jpda start Start Catalina under JPDA debugger echo run Start Catalina in the current window echo run -security Start in the current window with security manager echo start Start Catalina in a separate window echo start -security Start in a separate window with security manager echo stop Stop Catalina echo version What version of tomcat are you running? goto end :doDebug shift set _EXECJAVA= %_RUNJDB% set DEBUG_OPTS=-sourcepath "%CATALINA_HOME%\..\..\java" if not "" %1 "" == ""-security"" goto execCmd shift echo Using Security Manager set "SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy" goto execCmd :doRun shift if not "" %1 "" == ""-security"" goto execCmd shift echo Using Security Manager set "SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy" goto execCmd :doStart shift if not "%OS%" == "Windows_NT" goto noTitle if "%TITLE%" == "" set TITLE= Tomcat set _EXECJAVA= start "%TITLE%" %_RUNJAVA% goto gotTitle :noTitle set _EXECJAVA= start %_RUNJAVA% :gotTitle if not "" %1 "" == ""-security"" goto execCmd shift echo Using Security Manager set "SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy" goto execCmd :doStop shift set ACTION= stop set CATALINA_OPTS= goto execCmd :doVersion %_EXECJAVA% -classpath "%CATALINA_HOME%\lib\catalina.jar" org.apache.catalina.util. ServerInfo goto end :execCmd rem Get remaining unshifted command line arguments and save them in the set CMD_LINE_ARGS= :setArgs if "" %1 ""=="""" goto doneSetArgs set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1 shift goto setArgs :doneSetArgs rem Execute Java with the applicable properties if not "%JPDA%" == "" goto doJpda if not "%SECURITY_POLICY_FILE%" == "" goto doSecurity %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -Djava .endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION% goto end :doSecurity %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -Djava .endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Djava.security.manager -Djava.security.policy=="%SECURITY_POLICY_FILE%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION% goto end :doJpda if not "%SECURITY_POLICY_FILE%" == "" goto doSecurityJpda %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %JPDA_OPTS% %DEBUG_OPTS% -Djava .endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION% goto end :doSecurityJpda %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %JPDA_OPTS% %DEBUG_OPTS% -Djava .endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Djava.security.manager -Djava.security.policy=="%SECURITY_POLICY_FILE%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION% goto end :end
前三行的內(nèi)容是將當(dāng)前設(shè)置的變量進(jìn)行輸出,
echo Using CATALINA_BASE: "%CATALINA_BASE%" echo Using CATALINA_HOME: "%CATALINA_HOME%" echo Using CATALINA_TMPDIR: "%CATALINA_TMPDIR%"
CATALINA_BASE,CATALINA_HOME,CATALINA_TMPDIR這三個(gè)變量在startup.bat或者catalina.bat中已經(jīng)提前設(shè)置了,射出只是為了提示用戶當(dāng)前的運(yùn)行環(huán)境,接下來(lái)看181-187行的內(nèi)容:
if "" %1 "" == "" debug "" goto use_jdk echo Using JRE_HOME: "%JRE_HOME%" goto java_dir_displayed :use_jdk echo Using JAVA_HOME: "%JAVA_HOME%" :java_dir_displayed echo Using CLASSPATH: "%CLASSPATH%"
在解釋這段內(nèi)容之前,我建議大家要對(duì)setclasspath.bat中的內(nèi)容有所了解,因?yàn)閟etclasspath.bat中包含對(duì)與JRE_HOME,JAVA_HOME變量的邏輯處理和定義。這段內(nèi)容的意思就是說(shuō)如果catalina.bat接收到的第一個(gè)參數(shù)是debug,那么就到use_jdk節(jié)點(diǎn),由于一般情況下我們是用startup.bat腳本調(diào)用catalina.bat腳本,所以第一個(gè)參數(shù)應(yīng)該是start,所以應(yīng)該順序執(zhí)行到182行 echo Using JRE_HOME: "%JRE_HOME%",然后執(zhí)行到j(luò)ava_dir_displayed節(jié)點(diǎn),至于為什么 debug的時(shí)候不使用JRE_HOME這個(gè)變量 ,我們先記下,在以后的章節(jié)中在討論。
在189-194行中是設(shè)置一些變量,內(nèi)容如下:
set _EXECJAVA= %_RUNJAVA% set MAINCLASS=org.apache.catalina.startup. Bootstrap set ACTION= start set SECURITY_POLICY_FILE= set DEBUG_OPTS= set JPDA=
這里面要說(shuō)兩點(diǎn),%_RUNJAVA%變量和org.apache.catalina.startup.Bootstrap,其中%_RUNJAVA%是在setclasspath.bat文件中定義的,其值為"%JRE_HOME%\bin\java",
MAINCLASS寫過(guò)JAVA程序的人應(yīng)該都知道是做什么用的,關(guān)鍵是org.apache.catalina.startup.Bootstrap這個(gè)值是怎么來(lái)的,在哪里定義的,記得在catalina.bat中有過(guò)這么一個(gè)設(shè)置:CLASSPATH=%CLASSPATH%%CATALINA_HOME%\bin\bootstrap.jar,其中org.apache.catalina.startup.Bootstrap就是該jar包中的一個(gè)類。具體內(nèi)容以及意義不再此展開。
第196行-211行是對(duì)jpda()的處理,因?yàn)樵蹅儧](méi)有涉及,關(guān)于jdpa的內(nèi)容不在此展開,因?yàn)槲覀儾簧婕八蕴^(guò)此步驟:
if not "" %1 "" == ""jpda"" goto noJpda set JPDA= jpda if not "%JPDA_TRANSPORT%" == "" goto gotJpdaTransport set JPDA_TRANSPORT= dt_socket :gotJpdaTransport if not "%JPDA_ADDRESS%" == "" goto gotJpdaAddress set JPDA_ADDRESS=8000 :gotJpdaAddress if not "%JPDA_SUSPEND%" == "" goto gotJpdaSuspend set JPDA_SUSPEND= n :gotJpdaSuspend if not "%JPDA_OPTS%" == "" goto gotJpdaOpts set JPDA_OPTS=-agentlib :jdwp =transport=%JPDA_TRANSPORT%,address=%JPDA_ADDRESS%,server=y,suspend= %JPDA_SUSPEND% :gotJpdaOpts shift :noJpda
再次記下一個(gè)知識(shí)點(diǎn)JDPA。
下面到noJpda節(jié)點(diǎn),內(nèi)容如下:
if "" %1 "" == "" debug "" goto doDebug if "" %1 "" == "" run "" goto doRun if "" %1 "" == "" start "" goto doStart if "" %1 "" == ""stop"" goto doStop if "" %1 "" == ""version"" goto doVersion echo Usage: catalina ( commands ... ) echo commands: echo debug Start Catalina in a debugger echo debug -security Debug Catalina with a security manager echo jpda start Start Catalina under JPDA debugger echo run Start Catalina in the current window echo run -security Start in the current window with security manager echo start Start Catalina in a separate window echo start -security Start in a separate window with security manager echo stop Stop Catalina echo version What version of tomcat are you running? goto end
其中
if "" %1 "" == "" debug "" goto doDebug if "" %1 "" == "" run "" goto doRun if "" %1 "" == "" start "" goto doStart if "" %1 "" == ""stop"" goto doStop if "" %1 "" == ""version"" goto doVersion
是根據(jù)用戶輸入的具體命令,跳轉(zhuǎn)到具體的處理節(jié)點(diǎn),例如輸入的命令,那么就到doStart節(jié)點(diǎn),219行-230行的內(nèi)容是,如果你輸入的第一個(gè)參數(shù)不再預(yù)設(shè)的命令當(dāng)中,給你的提示:
echo Usage: catalina ( commands ... ) echo commands: echo debug Start Catalina in a debugger echo debug -security Debug Catalina with a security manager echo jpda start Start Catalina under JPDA debugger echo run Start Catalina in the current window echo run -security Start in the current window with security manager echo start Start Catalina in a separate window echo start -security Start in a separate window with security manager echo stop Stop Catalina echo version What version of tomcat are you running? goto end
下面先看232行-240行的doDebug節(jié)點(diǎn)的內(nèi)容:
:doDebug shift set _EXECJAVA= %_RUNJDB% set DEBUG_OPTS=-sourcepath "%CATALINA_HOME%\..\..\java" if not "" %1 "" == ""-security"" goto execCmd shift echo Using Security Manager set "SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy" goto execCmd
同樣%_RUNJDB%變量去setclasspath.bat文件中找定義,235行的內(nèi)容配置DEBUG_OPTS,接下來(lái)是安全策略的問(wèn)題,如果指定參數(shù)"-security",那么就需要加載安全策略文件,安全策略文件為%CATALINA_BASE%\conf\catalina.policy,內(nèi)容如下:

// Licensed to the Apache Software Foundation (ASF) under one or more // contributor license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright ownership. // The ASF licenses this file to You under the Apache License, Version 2.0 // (the "License"); you may not use this file except in compliance with // the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ============================================================================ // catalina.policy - Security Policy Permissions for Tomcat 7 // // This file contains a default set of security policies to be enforced ( by the // JVM) when Catalina is executed with the "-security" option. In addition // to the permissions granted here, the following additional permissions are // granted specific to each web application: // // * Read access to its document root directory // * Read, write and delete access to its working directory // // $Id: catalina.policy 981453 2010-08-02 11:00:51Z markt $ // ============================================================================ // ========== SYSTEM CODE PERMISSIONS ========================================= // These permissions apply to javac grant codeBase "file:${java.home}/lib/-" { permission java .security.AllPermission; } ; // These permissions apply to all shared system extensions grant codeBase "file:${java.home}/jre/lib/ext/-" { permission java .security.AllPermission; } ; // These permissions apply to javac when ${java.home] points at $JAVA_HOME/ jre grant codeBase "file:${java.home}/../lib/-" { permission java .security.AllPermission; } ; // These permissions apply to all shared system extensions when // ${java.home} points at $JAVA_HOME/ jre grant codeBase "file:${java.home}/lib/ext/-" { permission java .security.AllPermission; } ; // ========== CATALINA CODE PERMISSIONS ======================================= // These permissions apply to the daemon code grant codeBase "file:${catalina.home}/bin/commons-daemon.jar" { permission java .security.AllPermission; } ; // These permissions apply to the logging API // Note: If tomcat-juli.jar is in ${catalina.base} and not in ${catalina.home}, // update this section accordingly. // grant codeBase "file:${catalina.base}/bin/tomcat-juli.jar" {.. } grant codeBase "file:${catalina.home}/bin/tomcat-juli.jar" { permission java .io. FilePermission "${java.home}${file.separator}lib${file.separator}logging.properties", "read"; permission java .io. FilePermission "${catalina.base}${file.separator}conf${file.separator}logging.properties", "read"; permission java .io. FilePermission "${catalina.base}${file.separator}logs", "read, write"; permission java .io. FilePermission "${catalina.base}${file.separator}logs${file.separator}*", "read, write"; permission java .lang.RuntimePermission "shutdownHooks"; permission java .lang.RuntimePermission "getClassLoader"; permission java .lang.RuntimePermission "setContextClassLoader"; permission java .util.logging.LoggingPermission "control"; permission java .util.PropertyPermission "java.util.logging.config.class", "read"; permission java .util.PropertyPermission "java.util.logging.config.file", "read"; permission java .util.PropertyPermission "catalina.base", "read"; // Note: To enable per context logging configuration, permit read access to // the appropriate file. Be sure that the logging configuration is // secure before enabling such access. // E.g. for the examples web application: // permission java.io.FilePermission " ${catalina.base}${file.separator} // webapps${file.separator}examples${file.separator}WEB-INF // ${file.separator}classes${file.separator}logging.properties ", "read"; } ; // These permissions apply to the server startup code grant codeBase "file:${catalina.home}/bin/bootstrap.jar" { permission java .security.AllPermission; } ; // These permissions apply to the servlet API classes // and those that are shared across all class loaders // located in the "lib" directory grant codeBase "file:${catalina.home}/lib/-" { permission java .security.AllPermission; } ; // If using a per instance lib directory, i.e. ${catalina.base}/lib, // then the following permission will need to be uncommented // grant codeBase "file:${catalina.base}/lib/-" { // permission java.security.AllPermission; // }; // ========== WEB APPLICATION PERMISSIONS ===================================== // These permissions are granted by default to all web applications // In addition, a web application will be given a read FilePermission // and JndiPermission for all files and directories in its document root. grant { // Required for JNDI lookup of named JDBC DataSource's and // javamail named MimePart DataSource used to send mail permission java .util.PropertyPermission "java.home", "read"; permission java .util.PropertyPermission "java.naming.*", "read"; permission java .util.PropertyPermission "javax.sql.*", "read"; // OS Specific properties to allow read access permission java .util.PropertyPermission "os.name", "read"; permission java .util.PropertyPermission "os.version", "read"; permission java .util.PropertyPermission "os.arch", "read"; permission java .util.PropertyPermission "file.separator", "read"; permission java .util.PropertyPermission "path.separator", "read"; permission java .util.PropertyPermission "line.separator", "read"; // JVM properties to allow read access permission java .util.PropertyPermission "java.version", "read"; permission java .util.PropertyPermission "java.vendor", "read"; permission java .util.PropertyPermission "java.vendor.url", "read"; permission java .util.PropertyPermission "java.class.version", "read"; permission java .util.PropertyPermission "java.specification.version", "read"; permission java .util.PropertyPermission "java.specification.vendor", "read"; permission java .util.PropertyPermission "java.specification.name", "read"; permission java .util.PropertyPermission "java.vm.specification.version", "read"; permission java .util.PropertyPermission "java.vm.specification.vendor", "read"; permission java .util.PropertyPermission "java.vm.specification.name", "read"; permission java .util.PropertyPermission "java.vm.version", "read"; permission java .util.PropertyPermission "java.vm.vendor", "read"; permission java .util.PropertyPermission "java.vm.name", "read"; // Required for OpenJMX permission java .lang.RuntimePermission "getAttribute"; // Allow read of JAXP compliant XML parser debug permission java .util.PropertyPermission "jaxp.debug", "read"; // All JSPs need to be able to read this package permission java .lang.RuntimePermission "accessClassInPackage.org.apache.tomcat"; // Precompiled JSPs need access to these packages. permission java .lang.RuntimePermission "accessClassInPackage.org.apache.jasper.el"; permission java .lang.RuntimePermission "accessClassInPackage.org.apache.jasper.runtime"; permission java .lang. RuntimePermission "accessClassInPackage.org.apache.jasper.runtime.*"; // Precompiled JSPs need access to these system properties. permission java .util. PropertyPermission "org.apache.jasper.runtime.BodyContentImpl.LIMIT_BUFFER", "read"; permission java .util. PropertyPermission "org.apache.el.parser.COERCE_TO_ZERO", "read"; // The cookie code needs these. permission java .util. PropertyPermission "org.apache.catalina.STRICT_SERVLET_COMPLIANCE", "read"; permission java .util. PropertyPermission "org.apache.tomcat.util.http.ServerCookie.STRICT_NAMING", "read"; permission java .util. PropertyPermission "org.apache.tomcat.util.http.ServerCookie.FWD_SLASH_IS_SEPARATOR", "read"; // Applications using Comet need to be able to access this package permission java .lang.RuntimePermission "accessClassInPackage.org.apache.catalina.comet"; } ; // The Manager application needs access to the following packages to support the // session display functionality grant codeBase "file:${catalina.base}/webapps/manager/-" { permission java .lang.RuntimePermission "accessClassInPackage.org.apache.catalina"; permission java .lang.RuntimePermission "accessClassInPackage.org.apache.catalina.manager"; permission java .lang.RuntimePermission "accessClassInPackage.org.apache.catalina.manager.util"; } ; // You can assign additional permissions to particular web applications by // adding additional "grant" entries here, based on the code base for that // application, /WEB-INF/classes/, or /WEB-INF/lib/ jar files . // // Different permissions can be granted to JSP pages, classes loaded from // the /WEB-INF/classes/ directory, all jar files in the /WEB-INF/lib/ // directory, or even to individual jar files in the /WEB-INF/lib/ directory. // // For instance, assume that the standard "examples" application // included a JDBC driver that needed to establish a network connection to the // corresponding database and used the scrape taglib to get the weather from // the NOAA web server. You might create a "grant" entries like this: // // The permissions granted to the context root directory apply to JSP pages. // grant codeBase "file:${catalina.base}/webapps/examples/-" { // permission java. net .SocketPermission "dbhost.mycompany.com:5432", "connect"; // permission java. net .SocketPermission "*.noaa.gov:80", "connect"; // }; // // The permissions granted to the context WEB-INF/ classes directory // grant codeBase "file:${catalina.base}/webapps/examples/WEB-INF/classes/-" { // }; // // The permission granted to your JDBC driver // grant codeBase "jar:file:${catalina.base}/webapps/examples/WEB-INF/lib/driver.jar!/-" { // permission java. net .SocketPermission "dbhost.mycompany.com:5432", "connect"; // }; // The permission granted to the scrape taglib // grant codeBase "jar:file:${catalina.base}/webapps/examples/WEB-INF/lib/scrape.jar!/-" { // permission java. net .SocketPermission "*.noaa.gov:80", "connect"; // };
里面涉及到一些權(quán)限的設(shè)置,有興趣大家可以仔細(xì)研究。最終執(zhí)行execCmd節(jié)點(diǎn)的腳本。
242行-248行doRun節(jié)點(diǎn)內(nèi)容如下:
:doRun shift if not "" %1 "" == ""-security"" goto execCmd shift echo Using Security Manager set "SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy" goto execCmd
內(nèi)容同doDebug內(nèi)容相似,只是判斷是不是需要加載安全配置文件。
250行-263行的doStart節(jié)點(diǎn):
:doStart shift if not "%OS%" == "Windows_NT" goto noTitle if "%TITLE%" == "" set TITLE= Tomcat set _EXECJAVA= start "%TITLE%" %_RUNJAVA% goto gotTitle :noTitle set _EXECJAVA= start %_RUNJAVA% :gotTitle if not "" %1 "" == ""-security"" goto execCmd shift echo Using Security Manager set "SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy" goto execCmd
主要內(nèi)容就是,如果%OS%環(huán)境變量不是Windows_NT,那么不設(shè)置標(biāo)題,直接判斷是否需要加載安全配置文件,如果%OS%環(huán)境變量的值為Windows_NT,那么設(shè)置Title變量,如果沒(méi)有指定Title變量,默認(rèn)值為Tomcat,設(shè)置完_EXECJAVA變量以后,執(zhí)行execCmd節(jié)點(diǎn)的腳本。
265行-269行的doStop節(jié)點(diǎn),內(nèi)容比較簡(jiǎn)單,主要就是設(shè)置一下ACTION變量,內(nèi)容如下:
:doStop shift set ACTION= stop set CATALINA_OPTS= goto execCmd
271行-273行的doVersion節(jié)點(diǎn),就是調(diào)用了一下"%CATALINA_HOME%\lib\catalina.jar"中的org.apache.catalina.util.ServerInfo方法,內(nèi)容如下:
:doVersion %_EXECJAVA% -classpath "%CATALINA_HOME%\lib\catalina.jar" org.apache.catalina.util. ServerInfo goto end
下面真正的重點(diǎn)來(lái)了,execCmd節(jié)點(diǎn),其中有和startup.bat中處理參與一樣功能的節(jié)點(diǎn)setArgs,從279行-283行,循環(huán)讀出參數(shù)中的內(nèi)容追加到CMD_LINE_ARGS變量中,內(nèi)容如下:
set CMD_LINE_ARGS= :setArgs if "" %1 ""=="""" goto doneSetArgs set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1 shift goto setArgs
286行-300行的內(nèi)容就是真正的執(zhí)行方法了,先看內(nèi)容:
rem Execute Java with the applicable properties if not "%JPDA%" == "" goto doJpda if not "%SECURITY_POLICY_FILE%" == "" goto doSecurity %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -Djava .endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION% goto end :doSecurity %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -Djava .endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Djava.security.manager -Djava.security.policy=="%SECURITY_POLICY_FILE%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION% goto end :doJpda if not "%SECURITY_POLICY_FILE%" == "" goto doSecurityJpda %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %JPDA_OPTS% %DEBUG_OPTS% -Djava .endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION% goto end :doSecurityJpda %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %JPDA_OPTS% %DEBUG_OPTS% -Djava .endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Djava.security.manager -Djava.security.policy=="%SECURITY_POLICY_FILE%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION% goto end
是不是有點(diǎn)長(zhǎng),是不是有點(diǎn)看不懂,是不是覺得很麻煩,不要著急,我想一個(gè)辦法,更直觀的觀察這里面究竟是什么東西:下面我在這些腳本上添點(diǎn)東西,弄成這個(gè)樣子:
rem Execute Java with the applicable properties if not "%JPDA%" == "" goto doJpda if not "%SECURITY_POLICY_FILE%" == "" goto doSecurity %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -Djava .endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION% echo 1 %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION% goto end :doSecurity %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -Djava .endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Djava.security.manager -Djava.security.policy=="%SECURITY_POLICY_FILE%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION% echo 2 %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Djava.security.manager -Djava.security.policy=="%SECURITY_POLICY_FILE%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION% goto end :doJpda if not "%SECURITY_POLICY_FILE%" == "" goto doSecurityJpda %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %JPDA_OPTS% %DEBUG_OPTS% -Djava .endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION% echo 3 %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %JPDA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION% goto end :doSecurityJpda %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %JPDA_OPTS% %DEBUG_OPTS% -Djava .endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Djava.security.manager -Djava.security.policy=="%SECURITY_POLICY_FILE%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION% echo 4 %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %JPDA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Djava.security.manager -Djava.security.policy=="%SECURITY_POLICY_FILE%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION% goto end :end pause
其實(shí)很簡(jiǎn)單,就是把內(nèi)容輸出,然后為了能看清,我在后面加了個(gè)pause,嘿嘿,下面我從startup.bat啟動(dòng)catalina.bat以后看輸出結(jié)果:
Using CATALINA_BASE: "F:\apache-tomcat-7.0.8" Using CATALINA_HOME: "F:\apache-tomcat-7.0.8" Using CATALINA_TMPDIR: "F:\apache-tomcat-7.0.8\temp" Using JRE_HOME: "E:\Program Files\Java\jdk1.7.0_40" Using CLASSPATH: " F:\apache-tomcat-7.0.8\bin\bootstrap.jar;F:\apache-tomca t-7.0.8\bin\tomcat-juli.jar " 1 start "Tomcat" "E:\Program Files\Java\jdk1.7.0_40\bin\java" -Djava.util. loggi ng .config.file="F:\apache-tomcat-7.0.8\conf\logging.properties" -Djava.util. logg ing .manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=" F:\apa che-tomcat-7.0.8\endorsed " -classpath " F:\apache-tomcat-7.0.8\bin\bootstrap.jar; F:\apache-tomcat-7.0.8\bin\tomcat-juli.jar " -Dcatalina.base=" F:\apache-tomcat-7. 0.8 " -Dcatalina.home="F:\apache-tomcat-7.0.8" -Djava.io.tmpdir=" F:\apache-tomcat -7.0.8\temp " org.apache.catalina.startup.Bootstrap start 請(qǐng)按任意鍵繼續(xù) . . .
分析一下結(jié)果得出如下結(jié)論:
_EXECJAVA= start "Tomcat" "E:\Program Files\Java\jdk1.7.0_40\bin\java" JAVA_OPTS = -Djava.util.logging.config.file="F:\apache-tomcat-7.0.8\conf\logging.properties" -Djava .util.logging.manager=org.apache.juli. ClassLoaderLogManager CATALINA_OPTS = DEBUG_OPTS = -Djava .endorsed.dirs="F:\apache-tomcat-7.0.8\endorsed" -classpath "F:\apache-tomcat-7.0.8\bin\bootstrap.jar;F:\apache-tomcat-7.0.8\bin\tomcat-juli.jar" -Dcatalina .base="F:\apache-tomcat-7.0.8" -Dcatalina .home="F:\apache-tomcat-7.0.8" -Djava .io.tmpdir="F:\apache-tomcat-7.0.8\temp" MAINCLASS =org.apache.catalina.startup. Bootstrap CMD_LINE_ARGS = ACTION= start
至于其他情況,大家自己研究吧,希望能起到拋磚引玉的作用。在文中有三處疑問(wèn)(標(biāo)紅加粗字體),由于和本文關(guān)心不太大,在以后說(shuō)明,如果誰(shuí)愿意交流也可以寫在評(píng)論中, 昨天晚上寫了這些,腦袋都混亂了,好像如果有不正確的地方,歡迎大家指認(rèn)。
?
?
?
?
?
?
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
