startup.bat在最后调用catalina.bat,并且传递了start参数,设置了CATALINA_HOME和CURRENT_DIR俩个临时环境变量。那么catalina.bat都做了什么?

 @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 Start/Stop Script for the CATALINA Server
rem
rem Environment Variable Prerequisites
rem
rem Do not set the variables in this script. Instead put them into a script
rem setenv.bat in CATALINA_BASE/bin to keep your customizations separate.
rem
rem CATALINA_HOME May point at your Catalina "build" directory.
rem
rem CATALINA_BASE (Optional) Base directory for resolving dynamic portions
rem of a Catalina installation. If not present, resolves to
rem the same directory that CATALINA_HOME points to.
rem
rem CATALINA_OPTS (Optional) Java runtime options used when the "start",
rem "run" or "debug" command is executed.
rem Include here and not in JAVA_OPTS all options, that should
rem only be used by Tomcat itself, not by the stop process,
rem the version command etc.
rem Examples are heap size, GC logging, JMX ports etc.
rem
rem CATALINA_TMPDIR (Optional) Directory path location of temporary directory
rem the JVM should use (java.io.tmpdir). Defaults to
rem %CATALINA_BASE%\temp.
rem
rem JAVA_HOME Must point at your Java Development Kit installation.
rem Required to run the with the "debug" argument.
rem
rem JRE_HOME Must point at your Java Runtime installation.
rem Defaults to JAVA_HOME if empty. If JRE_HOME and JAVA_HOME
rem are both set, JRE_HOME is used.
rem
rem JAVA_OPTS (Optional) Java runtime options used when any command
rem is executed.
rem Include here and not in CATALINA_OPTS all options, that
rem should be used by Tomcat and also by the stop process,
rem the version command etc.
rem Most options should go into CATALINA_OPTS.
rem
rem JAVA_ENDORSED_DIRS (Optional) Lists of of semi-colon separated directories
rem containing some jars in order to allow replacement of APIs
rem created outside of the JCP (i.e. DOM and SAX from W3C).
rem It can also be used to update the XML parser implementation.
rem Defaults to $CATALINA_HOME/endorsed.
rem
rem JPDA_TRANSPORT (Optional) JPDA transport used when the "jpda start"
rem command is executed. The default is "dt_socket".
rem
rem JPDA_ADDRESS (Optional) Java runtime options used when the "jpda start"
rem command is executed. The default is .
rem
rem JPDA_SUSPEND (Optional) Java runtime options used when the "jpda start"
rem command is executed. Specifies whether JVM should suspend
rem execution immediately after startup. Default is "n".
rem
rem JPDA_OPTS (Optional) Java runtime options used when the "jpda start"
rem command is executed. If used, JPDA_TRANSPORT, JPDA_ADDRESS,
rem and JPDA_SUSPEND are ignored. Thus, all required jpda
rem options MUST be specified. The default is:
rem
rem -agentlib:jdwp=transport=%JPDA_TRANSPORT%,
rem address=%JPDA_ADDRESS%,server=y,suspend=%JPDA_SUSPEND%
rem
rem LOGGING_CONFIG (Optional) Override Tomcat's logging config file
rem Example (all one line)
rem set LOGGING_CONFIG="-Djava.util.logging.config.file=%CATALINA_BASE%\conf\logging.properties"
rem
rem LOGGING_MANAGER (Optional) Override Tomcat's logging manager
rem Example (all one line)
rem set LOGGING_MANAGER="-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager"
rem
rem TITLE (Optional) Specify the title of Tomcat window. The default
rem TITLE is Tomcat if it's not specified.
rem Example (all one line)
rem set TITLE=Tomcat.Cluster#.Server# [%DATE% %TIME%]
rem --------------------------------------------------------------------------- setlocal rem Suppress Terminate batch job on CTRL+C
if not ""%"" == ""run"" goto mainEntry
if "%TEMP%" == "" goto mainEntry
if exist "%TEMP%\%~nx0.run" goto mainEntry
echo Y>"%TEMP%\%~nx0.run"
if not exist "%TEMP%\%~nx0.run" goto mainEntry
echo Y>"%TEMP%\%~nx0.Y"
call "%~f0" %* <"%TEMP%\%~nx0.Y"
rem Use provided errorlevel
set RETVAL=%ERRORLEVEL%
del /Q "%TEMP%\%~nx0.Y" >NUL >&
exit /B %RETVAL%
:mainEntry
del /Q "%TEMP%\%~nx0.run" >NUL >& rem Guess CATALINA_HOME if not defined
set "CURRENT_DIR=%cd%"
if not "%CATALINA_HOME%" == "" goto gotHome
set "CATALINA_HOME=%CURRENT_DIR%"
if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
cd ..
set "CATALINA_HOME=%cd%"
cd "%CURRENT_DIR%"
:gotHome if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
echo The CATALINA_HOME environment variable is not defined correctly
echo This environment variable is needed to run this program
goto end
:okHome rem Copy CATALINA_BASE from CATALINA_HOME if not defined
if not "%CATALINA_BASE%" == "" goto gotBase
set "CATALINA_BASE=%CATALINA_HOME%"
:gotBase 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 not exist "%CATALINA_BASE%\bin\setenv.bat" goto checkSetenvHome
call "%CATALINA_BASE%\bin\setenv.bat"
goto setenvDone
:checkSetenvHome
if exist "%CATALINA_HOME%\bin\setenv.bat" call "%CATALINA_HOME%\bin\setenv.bat"
:setenvDone 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
call "%CATALINA_HOME%\bin\setclasspath.bat" %
if errorlevel goto end 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_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 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%" rem ----- Execute The Requested Command --------------------------------------- echo Using CATALINA_BASE: "%CATALINA_BASE%"
echo Using CATALINA_HOME: "%CATALINA_HOME%"
echo Using CATALINA_TMPDIR: "%CATALINA_TMPDIR%"
if ""%"" == ""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 ""%"" == ""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=
: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 ""%"" == ""debug"" goto doDebug
if ""%"" == ""run"" goto doRun
if ""%"" == ""start"" goto doStart
if ""%"" == ""stop"" goto doStop
if ""%"" == ""configtest"" goto doConfigTest
if ""%"" == ""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 configtest Run a basic syntax check on server.xml
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 ""%"" == ""-security"" goto execCmd
shift
echo Using Security Manager
set "SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy"
goto execCmd :doRun
shift
if not ""%"" == ""-security"" goto execCmd
shift
echo Using Security Manager
set "SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy"
goto execCmd :doStart
shift
if "%TITLE%" == "" set TITLE=Tomcat
set _EXECJAVA=start "%TITLE%" %_RUNJAVA%
if not ""%"" == ""-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 :doConfigTest
shift
set ACTION=configtest
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 ""%""=="""" goto doneSetArgs
set CMD_LINE_ARGS=%CMD_LINE_ARGS% %
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% %JPDA_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
:doSecurityJpda
%_EXECJAVA% %JAVA_OPTS% %JPDA_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 :end

  line    1  @echo off  关闭批处理输出

  line  94  setlocal  开始设置临时环境变量

  line  97  if not ""%1"" == ""run"" goto mainEntry  如果第一个参数不是run的话,goto mainEntry节点(第一个参数默认start,所以会直接goto mianEntry节点);否则继续。

  line  98-108  如果第一个参数是run的话才会被执行,其中加黑的103,105,107并未理解。

  line  98  if "%TEMP%" == "" goto mainEntry  如果没有TEMP环境变量的话,goto mianEntry节点;否则继续。我试了一下echo %TEMP%,得到的是*\AppData\Local\Temp,所以这个和startup.bat中的%OS%一样是存在的,继续line99

  line  99  if exist "%TEMP%\%~nx0.run" goto mainEntry  如果在%TEMP% 目录下有 %~nx0.run,goto mainEntry,但是%~nx0.run是什么呢?搜索了一下,%0就是本BAT的绝对路径,%~ 扩充删除任何引号,%~nx ::n文件名 ::x扩展名。试着写了个test.bat,内容是echo "%TEMP%\%~nx0.run",执行结果:*\AppData\Local\Temp\test.bat.run,所以这一行是如果在%TEMP%下有catalina.bat.run,goto mainEntry节点,我查了下对应目录下并没有catalina.bat.run,继续line100。

  line100  echo Y>"%TEMP%\%~nx0.run"  创建catalina.bat.run并写入Y。

  line101  if not exist "%TEMP%\%~nx0.run" goto mainEntry  如果%TEMP%下仍没有catalina.bat.run,goto mainEntry,但line100创建并写入了Y,继续下一行。

  line102  echo Y>"%TEMP%\%~nx0.Y"  创建catalina.bat.Y并写入Y。

  line103  call "%~f0" %* <"%TEMP%\%~nx0.Y"  试了下echo "%~f0",执行结果:*\Desktop\test.bat。%*是命令行传的所有参数,"%TEMP%\%~nx0.Y"是line102创建的文件内容为Y。所以line103做的事情就是catalina.bat自己调用自己,参数为Y。为什么呢????

  line105  set RETVAL=%ERRORLEVEL%  试了下echo %ERRORLEVEL%,执行结果:0,但是搜索了一下%ERRORLEVEL%是返回的错误码,0是成功,其他是失败。

  line106  del /Q "%TEMP%\%~nx0.Y" >NUL 2>&1  del /Q是安静模式删除,不要求确认。NUL是DOS下的一个虚拟设备,相当于一个文件(输入时立即结束,输出时仅作模拟)。2>&1,2是值错误输出,&1是标准输出,意思就是将错误输出重定向到标准输出中。>NUL 2>&1,就是将错误输入重定向到标准输出,重定向到NUL中。这行作用就是安静模式删除*\AppData\Local\Temp\test.bat.Y。

  DEL命令:

DEL [/P] [/F] [/S] [/Q] [/A[[:]attributes]] names
/P 删除每一个文件之前提示确认。
/F 强制删除只读文件。
/S 从所有子目录删除指定文件。
/Q 安静模式。删除全局通配符时,不要求确认。
/A 根据属性选择要删除的文件。

  line107  exit /B %RETVAL%  ,在cmd中输入了一下help exit,得到如下结果:

退出 CMD.EXE 程序(命令解释器)或当前批处理脚本。

EXIT [/B] [exitCode]

  /B          指定要退出当前批处理脚本而不是 CMD.EXE。如果从一个
批处理脚本外执行,则会退出 CMD.EXE exitCode 指定一个数字号码。如果指定了 /B,将 ERRORLEVEL
设成那个数字。如果退出 CMD.EXE,则用那个数字设置
过程退出代码。

  line108  :mainEntry  :mainEntry节点

  line109  del /Q "%TEMP%\%~nx0.run" >NUL 2>&1  安静模式删除*\AppData\Local\Temp\test.bat.run。

  为了搞明白103~107,我在catalina.bat中加入了几行输出,把catalina.bat.run的创建和删除注释掉了,如下:

 if not ""%"" == ""run"" goto mainEntry
if "%TEMP%" == "" goto mainEntry
if exist "%TEMP%\%~nx0.run" goto mainEntry
rem echo Y>"%TEMP%\%~nx0.run"
rem if not exist "%TEMP%\%~nx0.run" goto mainEntry
echo Y>"%TEMP%\%~nx0.Y"
echo ======================================
call "%~f0" %* <"%TEMP%\%~nx0.Y"
echo ======================================
rem Use provided errorlevel
set RETVAL=%ERRORLEVEL%
echo ====================================="%ERRORLEVEL%"
echo ====================================="%RETVAL%
del /Q "%TEMP%\%~nx0.Y" >NUL >&
exit /B %RETVAL%
:mainEntry
rem del /Q "%TEMP%\%~nx0.run" >NUL >&

  我直接启动catalina.bat run,用run做第一个参数,因为如果%TEMP%下没有catalina.bat.run的话会创建,然后我注释了line5,这样不会goto mainEntry节点,而是继续执行。line7会有输出,而后就没有了。line8 ,catalina.bat使用Y参数自己调用自己,然后走到line1,因为参数不是run而是Y,goto mainEntry节点。之后我将catalina.bat.Y修改为run试了下,会停留在line7一直输出=====1。那么line9~line15什么时候会执行呢?

我启动catalina.bat run,然后运行shutdown.bat,line9输出,%ERRORLEVEL%是0,catalina.bat.Y被删除,catalina.bat被停掉。简单扫了眼shutdown.bat,这个batch file 在最后call catalina.bat stop,即停掉了catalina.bat。

  line111~125  和startup.bat做的事情差不多,如果是从startup.bat启动的话,CURRENT_DIR和CATALINA_HOME俩个变量在startup里已经设置过,依然有效。

rem Guess CATALINA_HOME if not defined
set "CURRENT_DIR=%cd%"
if not "%CATALINA_HOME%" == "" goto gotHome
set "CATALINA_HOME=%CURRENT_DIR%"
if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
cd ..
set "CATALINA_HOME=%cd%"
cd "%CURRENT_DIR%"
:gotHome if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
echo The CATALINA_HOME environment variable is not defined correctly
echo This environment variable is needed to run this program
goto end
:okHome

111~125

  line127~130  如果没有CATALINA_BASE这个环境变量的话,把CATALINA_HOME的值给它(CATALINA_HOME这个环境变量我都没有提前配置,CATALINA_BASE肯定也不会配置)。

rem Copy CATALINA_BASE from CATALINA_HOME if not defined
if not "%CATALINA_BASE%" == "" goto gotBase
set "CATALINA_BASE=%CATALINA_HOME%"
:gotBase

127~130

  line132~134  set CLASSPATH=  设置CLASSPATH临时环境变量,注释为:Ensure that any user defined CLASSPATH variables are not used on startup, but allow them to be specified in setenv.bat, in rare case when it is needed. 大意是:确认在启动时不使用任何用户定义的CLASSPATH,但是在允许在setenv.bat里指定它们(CLASSPATH variables)。搜索了一下setenv.bat发现可以指定另外的JAVA_HOME和JAVA_OPTS等等环境变量。

  line136~142  如果用户在%CATALINA_HOME%\bin或者%CATALINA_BASE%\bin下建了setenv.bat就调用setenv.bat。

rem Get standard environment variables
if not exist "%CATALINA_BASE%\bin\setenv.bat" goto checkSetenvHome
call "%CATALINA_BASE%\bin\setenv.bat"
goto setenvDone
:checkSetenvHome
if exist "%CATALINA_HOME%\bin\setenv.bat" call "%CATALINA_HOME%\bin\setenv.bat"
:setenvDone

136~142

  line144~151  调用%CATALINA_HOME%\bin\setclasspath.bat,获取java相关环境变量。

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
call "%CATALINA_HOME%\bin\setclasspath.bat" %
if errorlevel goto end

144~151

  line145  if exist "%CATALINA_HOME%\bin\setclasspath.bat" goto okSetclasspath  如果文件存在,goto okSetclasspath节点,否则执行line146~147后goto end节点退出本次批处理。

  line150  call "%CATALINA_HOME%\bin\setclasspath.bat" %1  调用%CATALINA_HOME%\bin\setclasspath.bat,参数是catalina.bat的第一个参数(即从startup.bat拿到的start)。

 @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 Make sure prerequisite environment variables are set rem In debug mode we need a real JDK (JAVA_HOME)
if ""%"" == ""debug"" goto needJavaHome rem Otherwise either JRE or JDK are fine
if not "%JRE_HOME%" == "" goto gotJreHome
if not "%JAVA_HOME%" == "" goto gotJavaHome
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 :needJavaHome
rem Check if we have a usable JDK
if "%JAVA_HOME%" == "" goto noJavaHome
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
set "JRE_HOME=%JAVA_HOME%"
goto okJava :noJavaHome
echo The JAVA_HOME environment variable is not defined correctly.
echo It is needed to run this program in debug mode.
echo NB: JAVA_HOME should point to a JDK not a JRE.
goto exit :gotJavaHome
rem No JRE given, use JAVA_HOME as JRE_HOME
set "JRE_HOME=%JAVA_HOME%" :gotJreHome
rem Check if we have a usable JRE
if not exist "%JRE_HOME%\bin\java.exe" goto noJreHome
if not exist "%JRE_HOME%\bin\javaw.exe" goto noJreHome
goto okJava :noJreHome
rem Needed at least a JRE
echo The JRE_HOME environment variable is not defined correctly
echo This environment variable is needed to run this program
goto exit :okJava
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=%CATALINA_HOME%\endorsed"
:gotEndorseddir rem Don't override _RUNJAVA if the user has set it previously
if not "%_RUNJAVA%" == "" goto gotRunJava
rem Set standard command for invoking Java.
rem Also note the quoting as JRE_HOME may contain spaces.
set _RUNJAVA="%JRE_HOME%\bin\java.exe"
:gotRunJava rem Don't override _RUNJDB if the user has set it previously
rem Also note the quoting as JAVA_HOME may contain spaces.
if not "%_RUNJDB%" == "" goto gotRunJdb
set _RUNJDB="%JAVA_HOME%\bin\jdb.exe"
:gotRunJdb goto end :exit
exit /b :end
exit /b

setclasspath.bat

  setclasspath.bat比较简单。In debug mode we need a real JDK (JAVA_HOME),如果没有JRE_HOME和JAVA_HOME,goto exit等等,设置了%JAVA_ENDORSED_DIRS%、%_RUNJAVA%和%_RUNJDB%,执行完毕返回结果0或1。

  line151  if errorlevel 1 goto end  如果setclasspath.bat的结果是1,goto end节点,退出本次批处理。

  line153~159  如果有%CLASSPATH%的话,CLASSPATH=";" + %CATALINA_HOME%\bin\bootstrap.jar;否则CLASSPATH=%CATALINA_HOME%\bin\bootstrap.jar。

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"

153~159

  line161~163  如果没有%CATALINA_TMPDIR%环境变量的话,设置%CATALINA_TMPDIR%=%CATALINA_BASE%\temp。

if not "%CATALINA_TMPDIR%" == "" goto gotTmpdir
set "CATALINA_TMPDIR=%CATALINA_BASE%\temp"
:gotTmpdir

161~163

  line165~172  把tomcat-juli.jar写进CLASSPATH里。

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

165~172

  line174~184  对日志的处理,给%JAVA_OPTS%加上了%LOGGING_CONFIG% %LOGGING_MANAGER%。

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%"

174~184

  line186  rem ----- Execute The Requested Command   执行请求。

  line188~190  输出了CATALINA_BASE、CATALINA_HOME和CATALINA_TMPDIR,从上边可以看出,如果没有设置CATALINA_BASE环境变量的话,CATALINA_BASE=CATALINA_HOME,而CATALINA_TMPDIR=在CATALINA_BASE\temp,而CATALINA_HOME就是catalina.bat的目录(startup.bat一般和catalina.bat在一起)。

  line190~197  如果第一个参数是debug,输出%JAVA_HOME%;否则输出%JRE_HOME%,输出拼接的%CLASSPATH%。

echo Using CATALINA_BASE:   "%CATALINA_BASE%"
echo Using CATALINA_HOME: "%CATALINA_HOME%"
echo Using CATALINA_TMPDIR: "%CATALINA_TMPDIR%"
if ""%"" == ""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%"

188~197

  line199~204  设置了6个变量。_EXECJAVA=%_RUNJAVA%,%_RUNJAVA%这个环境变量是在setclasspath.bat中设置的,值为%JRE_HOME%\bin\java.exe;MAINCLASS=org.apache.catalina.startup.Bootstrap,这个类在%CATALINA_HOME%\bin\bootstarp.jar;ACTION=start;其他3个变量没有赋值。

set _EXECJAVA=%_RUNJAVA%
set MAINCLASS=org.apache.catalina.startup.Bootstrap
set ACTION=start
set SECURITY_POLICY_FILE=
set DEBUG_OPTS=
set JPDA=

199~204

  line206~221  是对jdpa的一些操作,搜了一下jdpa的简介,是调试java的api。

if not ""%"" == ""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=
: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

206~221

  jdpa简介:

Java平台调试器架构(英语:Java Platform Debugger Architecture,JPDA)是一组用于调试Java代码的API。

Java调试器接口(Java Debugger Interface,JDI)——定义了一个高层次Java接口,开发人员可以利用JDI轻松编写远程调试工具。
Java虚拟机工具接口(Java Virtual Machine Tools Interface,JVMTI)——定义了一个原生(native)接口,可以对运行在Java虚拟机的应用程序检查状态、控制运行。
Java虚拟机调试接口(JVMDI)——JVMDI在J2SE .0中被JVMTI取代,并在Java SE 6中被移除。
Java调试线协议(JDWP)——定义了调试对象(一个 Java 应用程序)和调试器进程之间的通信协议。

  line223~242  判断catalina.bat的第一个参数,goto 对应的节点。如果第一个参数不是debug、run、start、stop、configtest、version,goto end,本次批处理结束。

if ""%"" == ""debug"" goto doDebug
if ""%"" == ""run"" goto doRun
if ""%"" == ""start"" goto doStart
if ""%"" == ""stop"" goto doStop
if ""%"" == ""configtest"" goto doConfigTest
if ""%"" == ""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 configtest Run a basic syntax check on server.xml
echo version What version of tomcat are you running?
goto end

223~242

  line244~252  doDebug节点

  line245  shift  表示批处理文件中替换参数左移一个位置,后面的替换参数陆续填补上去。

  line246  set _EXECJAVA=%_RUNJDB%  这个变量在line199已经设置过,%_RUNJAVA%这个环境变量是在setclasspath.bat中设置的,值为%JRE_HOME%\bin\java.exe。

  line247  set DEBUG_OPTS=-sourcepath "%CATALINA_HOME%\..\..\java"  

  line248  if not ""%1"" == ""-security"" goto execCmd  因为245有一个shift命令,所以此处的%1是catalina.bat启动时的第二个参数。如果%1不是-security的话,goto execCmd节点;否则继续。

  line249  shift  参数再次左移

  line251  set "SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy"  这个SECURITY_POLICY_FILE赋值。

:doDebug
shift
set _EXECJAVA=%_RUNJDB%
set DEBUG_OPTS=-sourcepath "%CATALINA_HOME%\..\..\java"
if not ""%"" == ""-security"" goto execCmd
shift
echo Using Security Manager
set "SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy"
goto execCmd

debug节点244~252

  line254~260  doRun节点,如果启动时第二个参数是-security,set "SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy";否则直接goto execCmd节点。

:doRun
shift
if not ""%"" == ""-security"" goto execCmd
shift
echo Using Security Manager
set "SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy"
goto execCmd

dorun节点254~260

  line262~270  doStart节点。设置TITLE=TOMCAT,设置_EXECJAVA=start "TOMCAT" %_RUNJAVA%,这样cmd窗口的title会变为“TOMCAT”。如果启动时第二个参数是-security,set "SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy";否则直接goto execCmd节点。

:doStart
shift
if "%TITLE%" == "" set TITLE=Tomcat
set _EXECJAVA=start "%TITLE%" %_RUNJAVA%
if not ""%"" == ""-security"" goto execCmd
shift
echo Using Security Manager
set "SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy"
goto execCmd

dostart262~270

  line272~276  doStop节点,改变ACTION=stop,CATALINA_OPTS=,goto execCmd节点。

:doStop
shift
set ACTION=stop
set CATALINA_OPTS=
goto execCmd

dostop272~270

  line278~282  doConfigTest节点,改变ACTION=configtest,CATALINA_OPTS=,goto execCmd节点。

:doConfigTest
shift
set ACTION=configtest
set CATALINA_OPTS=
goto execCmd

doConfigTest278~282

  line284~286  doVersion节点,执行line285后goto end节点,本次批处理结束。

  line285  %_EXECJAVA% -classpath "%CATALINA_HOME%\lib\catalina.jar" org.apache.catalina.util.ServerInfo  等同于java -classpath "*\catalina.jar" org.apache.catalina.util.ServerInfo

:doVersion
%_EXECJAVA% -classpath "%CATALINA_HOME%\lib\catalina.jar" org.apache.catalina.util.ServerInfo
goto end

doVersion284~286

  反编译后的ServerInfo(片段):

...
public static void main(String[] args) {
System.out.println("Server version: " + getServerInfo());
System.out.println("Server built: " + getServerBuilt());
System.out.println("Server number: " + getServerNumber());
System.out.println("OS Name: " + System.getProperty("os.name"));
System.out.println("OS Version: " + System.getProperty("os.version"));
System.out.println("Architecture: " + System.getProperty("os.arch"));
System.out.println("JVM Version: " + System.getProperty("java.runtime.version"));
System.out.println("JVM Vendor: " + System.getProperty("java.vm.vendor"));
}

 /**
  * 从
ServerInfo.properties读取服务器信息,如果读取失败会有默认返回。
  */
static {
Properties props = new Properties();
    InputStream is = null;
try {
is = ServerInfo.class.getResourceAsStream("/org/apache/catalina/util/ServerInfo.properties"); // 这个配置文件里只有server.info, server.built, server.number3个属性
props.load(is);
serverInfo = props.getProperty("server.info");
serverBuilt = props.getProperty("server.built");
serverNumber = props.getProperty("server.number");
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
} finally {
if (is != null)
try {
is.close();
}
catch (IOException e) {
}
}
if (serverInfo == null)
serverInfo = "Apache Tomcat 7.0.x-dev";
if (serverBuilt == null)
serverBuilt = "unknown";
if (serverNumber == null)
serverNumber = "7.0.x";
}
...

  line289~297  execCmd节点,拼接剩余的参数给CMD_LINE_ARGS,和startup.bat中一样。

  line299~313  以4种方式之一启动bootstarp.jar,启动后都goto end节点,本次批处理结束,设置的临时环境变量失效。

  line302  %_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%  这种启动方式是没有jdpa和SECURITY_POLICY_FILE的启动。这种模式的%_EXECJAVA%=start "Tomcat" "%JRE_HOME%\bin\java.exe";%JAVA_OPTS%是line174~184对日志的处理;CATALINA_OPTS="";%DEBUG_OPTS%="";%JAVA_ENDORSED_DIRS%在setclasspath.bat设置为%CATALINA_HOME%\endorsed;%CLASSPATH%是拼接了bootstrap.jar和tomcat-juli.jar俩个jar包的绝对路径;%MAINCLASS%="org.apache.catalina.startup.Bootstrap"是bootstrap.jar的要启动的main方法所在类;%CMD_LINE_ARGS%是catalina.bat启动时传入参数拼接而成(从第三个参数开始拼接,因为doStart节点的line263和line267有2处shift),一般为空;%ACTION%=start。简言,就是启动了bootstrap.jar,main方法是org.apache.catalina.startup.Bootstrap,参数肯定会有一个start(如果有其他参数,这个会在最后)。

  line305  %_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%  这种启动方式是没有jdpa但是有SECURITY_POLICY_FILE的启动。比line302多了-Djava.security.policy=="%SECURITY_POLICY_FILE%",%SECURITY_POLICY_FILE%=%CATALINA_BASE%\conf\catalina.policy,catalina.policy是大约TOMCAT的权限控制之类。

  line309  %_EXECJAVA% %JAVA_OPTS% %JPDA_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%  这种启动方式有jdpa无SECURITY_POLICY_FILE,其中%JPDA_OPTS%在line206~221设置。

  line312  %_EXECJAVA% %JAVA_OPTS% %JPDA_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%  这种启动方式有jpda和SECURITY_POLICY_FILE

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% %JPDA_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
:doSecurityJpda
%_EXECJAVA% %JAVA_OPTS% %JPDA_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

299~313

  line315  :end  end节点。

  这个批处理比startup.bat复杂的多,tomcat允许我们在%CATALINA_BASE%\bin\setenv.bat设置环境变量,读取%CATALINA_HOME%\bin\setclasspath.bat获取java相关的环境变量,拼接classpath,设置日志相关,设置JPDA_OPTS相关,%CATALINA_BASE%\conf\catalina.policy的权限控制,如果要查看版本信息,会启动%CATALINA_HOME%\lib\catalina.jar下的org.apache.catalina.util.ServerInfo等等最终,也是一般情况(startup.bat启动catalina.bat)会在最后启动bootstrap.jar的org.apache.catalina.startup.Bootstrap类,参数为start。

(二)catalina.bat的更多相关文章

  1. [Tomcat 源码分析系列] (二) : Tomcat 启动脚本-catalina.bat

    概述 Tomcat 的三个最重要的启动脚本: startup.bat catalina.bat setclasspath.bat 上一篇咱们分析了 startup.bat 脚本 这一篇咱们来分析 ca ...

  2. [Tomcat 源码分析系列] (附件) : catalina.bat 脚本

    摘自 apache-tomcat-8.0.39-src 源码包中的 catalina.bat 脚本内容 @echo off rem Licensed to the Apache Software Fo ...

  3. tomcat启动批处理——catalina.bat

    这个批处理才是tomcat服务器启动跟关闭的核心脚本.其中包括....(各种变量),此节将详细讲解这个批处理的逻辑. 先看看第一部分脚本: ****************************** ...

  4. tomcat启动(一)startup.bat|catalina.bat分析

    环境:windows X64位 Tomcat8.0.47 bootstrap.jar是tomcat的内核 开始位置 startup.bat 查看文本 具体的批处理脚本语法可以查看我整理的文章 http ...

  5. 查看tomcat启动文件都干点啥---catalina.bat(转)

    在上一次查看tomcat启动文件都干点啥一文中,我们总结出,startup.bat文件的作用就是找到catalina.bat文件,然后把参数传递给它,在startup.bat中,调用catalina. ...

  6. 查看tomcat启动文件都干点啥---catalina.bat

    在上一次查看tomcat启动文件都干点啥一文中,我们总结出,startup.bat文件的作用就是找到catalina.bat文件,然后把参数传递给它,在startup.bat中,调用catalina. ...

  7. Tomcat启动脚本(2)catalina.bat

    @echo off rem Licensed to the Apache Software Foundation (ASF) under one or more rem contributor lic ...

  8. 远程部署项目,修改catalina.bat文件 完美解决在代理服务器上HttpURLConnection 调接口超时的问题

    远程给客户部署项目,运行时程序调外部接口时总是出不去,经过不懈努力,后来发现客户那边的网络走的是代理,于是在代码中加下面代码: //设置代理 System.setProperty("http ...

  9. 深入刨析tomcat 之---第12篇 how tomcat works( 第17章 ) 解析catalina.bat 梳理启动流程

    我们如何启动tomcat呢? 答案是双击startup.bat文件,这个文件在bin目录下 @echo off    不显示批处理命令 rem Licensed to the Apache Softw ...

随机推荐

  1. Windows Azure初体验

    目前在IT界,云这个概念的第一意思不再是词典里的解释了.不过它们还是有相同点的——也许确实会酝酿出一块大蛋糕,可也是飘在天上,众神分食之,与我等P民无关.所谓云,不过是网络时代发展到一定阶段的必然产物 ...

  2. 裸奔Spring(1)

    pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w ...

  3. 安卓基于WifiScanner的签到APP

    没图说个JB?首先上图:      友情提醒:后台数据库使用的是Bmob后端云 主要设计思路:首先选一个附近的wifi,输入签到码,进行签到. 签到之后会启动一个后台线程每隔一段时间扫描附近wifi, ...

  4. cs11_c++_lab4b

    SparseVector.hh class SparseVector { private: //结构体不一定会用到,不用初始化 struct node { int index; int value; ...

  5. Leetcode3:Longest Substring Without Repeating Characters@Python

    Given a string, find the length of the longest substring without repeating characters. Examples: Giv ...

  6. ThinkPHP单字母函数(快捷方法)使用总结

    在ThinkPHP中有许多使用简便的单字母函数(即快捷方法),可以很方便开发者快速的调用,但是字母函数却不方便记忆,本文将所有的字母函数总结一下,以方便以后查找. 1.U() URL组装 支持不同UR ...

  7. Redis3.0.1 Stable版本的集群部署(Mac)

    本文档基于如下原始文档(CentOS)创建: http://blog.csdn.net/xu470438000/article/details/42971091 修改了一些路径的错误,补全了一些命令执 ...

  8. MFC中无边框窗口的拖动

      void CXXXXDialog::OnLButtonDown(UINT nFlags, CPoint point) { PostMessage(WM_NCLBUTTONDOWN, HTCAPTI ...

  9. codeforces 742D Arpa's weak amphitheater and Mehrdad's valuable Hoses ——(01背包变形)

    题意:给你若干个集合,每个集合内的物品要么选任意一个,要么所有都选,求最后在背包能容纳的范围下最大的价值. 分析:对于每个并查集,从上到下滚动维护即可,其实就是一个01背包= =. 代码如下: #in ...

  10. select标签非空验证,第一个option value=""即可

    select标签非空验证,第一个option value=""即可,否则不能验证