공부하게 된 계기는 팀장님의 피드백으로 인해서 많은 생각을 하게 되었습니다.

그리고 코드를 분석하는 방법에 대해서도 결과부터가 아니라 순차적으로 분석해야 한다는 느낌을 많이 받았습니다.

 

기존에 개발하면서 결과적인 시각으로 많이 바라본게 아닌가 라는 생각을 많이 하게되었습니다. 아직 조금 그러한 습관이 남아 있어서 천천히 없애도록 노력해야겠다는 생각이 들었습니다. (한번에 없어지는게 이상한거겠지만 ㅎㅎ 일단은 조금씩 바꾸면 언젠간 바뀐다고 믿는 성격이어서 열심히 해볼생각입니다. 생각해보면 블로그 작성이나 공부하는 습관들도 처음부터 생겼던건 아니었으니까요. ㅎㅎ) 

 

과연 war 실행의 구동원리를 정확하게 이해하고 있는가? 에 대해서 다시 한번 돌아보게 되었습니다.

조금 더 섬세하게 체크 해야겟다는 생각이 많이 들었습니다.

 

톰캣 이용되는곳?

 

정확하게 웹이 실행될때 일반적으로 톰캣을 이용하여 사용하는경우가 많다.

물론  iis 서버 같은걸로 할수 있지만 일단 저희 회사에선 톰캣을 이용하기도 하고 많은 회사들이 톰캣을 이용하기 때문에 

톰캣동작에 대해서 먼저 정리해보도록 하겠습니다.

 

톰캣(tomcat) 설치 링크:

https://tomcat.apache.org/

 

Apache Tomcat® - Welcome!

The Apache Tomcat® software is an open source implementation of the Jakarta Servlet, Jakarta Server Pages, Jakarta Expression Language, Jakarta WebSocket, Jakarta Annotations and Jakarta Authentication specifications. These specifications are part of the

tomcat.apache.org

기본적인 형태는 이렇습니다.

/bin            -   시작, 종료 및 기타 스크리트 파일

/conf          -  구성 파일 및 관련 DTD, 여기서 중요한 파일은 sever.xml입니다. 컨테이너 기본 구성 파일입니다.

/logs          -  로그 파일은 기본적으로 여기있습니다.

/webapps  - 웹앱은 여기에 있습니다.

 

Catalina_Home 및 Catalina_Base?

  • catalina_home: 톰캣 설치 루트를 나타냅니다. ( 예: /home/tomcat/apache-tomcat-9.0x, C:\program Files\ apache-tomcat-9.0x )
  • catalina_base:특정 Tomact 인스턴스의 런타임 구성 루트를 나타냅니다. 한 시스템에 여러 Tomcat 인스턴스를 갖고 싶다면 이 Catlian_base 속성을 사용하면 됩니다.
  • 속성을 다른 위치로 설정하면 catilina_home 위치에 .jar 파일이나 바이너리 파일과 정적 소스가 포함됩니다. catalina_base위치에는 구성 파일, 로그 파일, 배포된 애플리케이션 및 기타 런타임 요구 사항이 포함됩니다.

Catalina_base를 사용하는 이유?

기본적으로 Catalina_home과 Catlina_base는 동일한 디렉토리를 가리킵니다. 하나의 시스템에서 여러 톰캣 인스턴스를 실행해야하는 경우 Catalina_base를 수동으로 설정하십시오.

  • 최신버전의 톰캣으로 업그레이드 관리가 더 쉬워졌습니다. 단일 Catalina_home위치를 가진 모든 인스턴스는 하나의 파일 및 바이너리 파일 세트를 공유하므로, .jar파일을 최신 버전으로 쉽게 업그레이드하고 동일한 Catalina_home 디렉터리를 사용하는 모든 톰캣 인스턴스에 변경사항을 전파할수 있습니다.
  • 동일한 정적 .jar 파일의 중복을 방지합니다.
  • sentenv운영 체제에 따라 쉘 또는 bat 스크립트 파일과 같은 특정 설정을 공유할수 있습니다.

코드에 대해서 한번 분석 해보겠습니다.

우선 startup.bat을 실행하면 

보시면 rem 은 주석이므로 쓸데 없는 앞부분은 지웟습니다.

@echo off

rem ---------------------------------------------------------------------------
rem Start script for the CATALINA Server
rem ---------------------------------------------------------------------------

setlocal

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

set "EXECUTABLE=%CATALINA_HOME%\bin\catalina.bat"

rem Check that target executable exists

if exist "%EXECUTABLE%" goto okExec
echo Cannot find "%EXECUTABLE%"
echo This file is needed to run this program
goto end
:okExec

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

call "%EXECUTABLE%" start %CMD_LINE_ARGS%

:end

 

코드를 보시면 

startup.bat->catalina.bat을 호출하죠. 

catalina.bat을 한번 보겠습니다. 마찬가지로 앞부분 rem은 조금 삭제하겠습니다.

 

@echo off

setlocal

rem Suppress Terminate batch job on CTRL+C
if not ""%1"" == ""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 2>&1
exit /B %RETVAL%
:mainEntry
del /Q "%TEMP%\%~nx0.run" >NUL 2>&1

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 neither CATALINA_HOME nor CATALINA_BASE contains a semi-colon
rem as this is used as the separator in the classpath and Java provides no
rem mechanism for escaping if the same character appears in the path. Check this
rem by replacing all occurrences of ';' with '' and checking that neither
rem CATALINA_HOME nor CATALINA_BASE have changed
if "%CATALINA_HOME%" == "%CATALINA_HOME:;=%" goto homeNoSemicolon
echo Using CATALINA_HOME:   "%CATALINA_HOME%"
echo Unable to start as CATALINA_HOME contains a semicolon (;) character
goto end
:homeNoSemicolon

if "%CATALINA_BASE%" == "%CATALINA_BASE:;=%" goto baseNoSemicolon
echo Using CATALINA_BASE:   "%CATALINA_BASE%"
echo Unable to start as CATALINA_BASE contains a semicolon (;) character
goto end
:baseNoSemicolon

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" %1
if errorlevel 1 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 "%JSSE_OPTS%" == "" goto gotJsseOpts
set JSSE_OPTS="-Djdk.tls.ephemeralDHKeySize=2048"
:gotJsseOpts
set "JAVA_OPTS=%JAVA_OPTS% %JSSE_OPTS%"

rem Register custom URL handlers
rem Do this here so custom URL handles (specifically 'war:...') can be used in the security policy
set "JAVA_OPTS=%JAVA_OPTS% -Djava.protocol.handler.pkgs=org.apache.catalina.webresources"

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

if not "%LOGGING_MANAGER%" == "" goto noJuliManager
set LOGGING_MANAGER=-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
:noJuliManager

rem Configure JAVA 9 specific start-up parameters
set "JDK_JAVA_OPTIONS=%JDK_JAVA_OPTIONS% --add-opens=java.base/java.lang=ALL-UNNAMED"
set "JDK_JAVA_OPTIONS=%JDK_JAVA_OPTIONS% --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED"

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=localhost: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"" == ""configtest"" goto doConfigTest
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   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 ""%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 "%TITLE%" == "" set TITLE=Tomcat
set _EXECJAVA=start "%TITLE%" %_RUNJAVA%
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

: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 ""%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% %LOGGING_CONFIG% %LOGGING_MANAGER% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION%
goto end
:doSecurity
%_EXECJAVA% %LOGGING_CONFIG% %LOGGING_MANAGER% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -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% %LOGGING_CONFIG% %LOGGING_MANAGER% %JAVA_OPTS% %JPDA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION%
goto end
:doSecurityJpda
%_EXECJAVA% %LOGGING_CONFIG% %LOGGING_MANAGER% %JAVA_OPTS% %JPDA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -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

 

엄청많죠 여기서 조금 핵심적으로 봐야하는게 

setenv.bat -> setclasspath.bat -> bootstrap.jar -> tomcat-juli.jar 입니다.

 

setenv.bat 는 JAVA_OPTS, CATALINA_OPTS등의 환경변수 설정을 하는데 이용됩니다.

이 동작이 jvm의 동작에도 영향을 줍니다.

 

setclassthpath.bat은 java class 와 libarary에 대한 class_path  설정을 합니다. 

jar 파일의 경로가 포함될수 있습니다.

 

bootstrap.jarTomcat 서버의 초기화와 시작을 담당합니다.

https://tomcat.apache.org/tomcat-8.5-doc/api/org/apache/catalina/startup/Bootstrap.html

 

Bootstrap (Apache Tomcat 8.5.98 API Documentation)

public final class Bootstrap extends Object Bootstrap loader for Catalina. This application constructs a class loader for use in loading the Catalina internal classes (by accumulating all of the JAR files found in the "server" directory under "catalina.hom

tomcat.apache.org

 

tomcat-juli.jar는 로깅시스템 처리하는데 사용됩니다.

bootstarp.jar와 함께 클래스 패스에 포함되어 로그 관리 기능을 제공합니다.

 

그렇다면 bootstrap.jar 이 server.xml을 읽어와야하는데요. 이부분을 한번 확인해보겠습니다.

 

https://tomcat.apache.org/download-90.cgi

 

Apache Tomcat® - Apache Tomcat 9 Software Downloads

Welcome to the Apache Tomcat® 9.x software download page. This page provides download links for obtaining the latest version of Tomcat 9.0.x software, as well as links to the archives of older releases. Unsure which version you need? Specification version

tomcat.apache.org

zip파일을 읽어와서 압축푼후 코드를 한번 보겠습니다.

 

bootstarp.jar 파일이 아닌 코드로 보면 

/java/org/apache/catalina/startip/Catalina.java 파일을 보면요.

 

conf/server.xml을 읽어옵니다. 

주석은 제거하고 

<?xml version="1.0" encoding="UTF-8"?>

<Server port="8005" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />

  <GlobalNamingResources>
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" />
  </GlobalNamingResources>

  <Service name="Catalina">

    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />

    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

    <Engine name="Catalina" defaultHost="localhost">

      <Realm className="org.apache.catalina.realm.LockOutRealm">
   
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
      </Realm>

      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">

        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log" suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />

      </Host>
    </Engine>
  </Service>
</Server>

 

 xml 코드를 보시면 사용되는 port 번호 appbase webapps 파일 위치나 host 읽어올수 잇게 하는거죠.

 

정리하면 

 

startup.bat->catlina.bat->  (setenv.bat -> setclasspath.bat) 환경설정 -> (bootstrap.jar ( read file server.xml )  )앱서버 실행 -> tomcat-juli.jar 로깅 

 

이런식으로 이해하면 좋을것 같습니다. 잘못된부분 지적 부탁드리겠습니다.

 

그리고 조금 톰켓 부분을 수정하는 부분이 있으면 분석하면서 더 작성도 해보도록 하겠습니다.

 

참고:

 

https://tomcat.apache.org/tomcat-9.0-doc/introduction.html

 

Apache Tomcat 9 (9.0.85) - Introduction

Before you start using CATALINA_BASE, first consider and create the directory tree used by CATALINA_BASE. Note that if you do not create all the recommended directories, Tomcat creates the directories automatically. If it fails to create the necessary dire

tomcat.apache.org

 

' > Spring' 카테고리의 다른 글

Spring Data JPA - 핵심 개념  (0) 2024.02.03
Spring Data JPA에 대해서  (0) 2024.02.03
Gradle에서 compileOnly와 implementation 차이  (0) 2024.01.09
multiple gradle 빌드 시키기!  (0) 2024.01.08
gradle과 maven의 차이  (1) 2024.01.08

+ Recent posts