Tomcat

Tomcat : Overview

peter.j 2022. 2. 27. 20:29

톰캣은 자바진영의 대표적인 WAS입니다.

여기서 WAS란, 쉽게 설명하면 요청을 받는 서버역할도 하면서 동적인 결과를 만들어내는 애플리케이션의 역할도 하는 서버입니다.

톰캣은 서블릿 컨테이너라고도 불리우는데, 컨테이너는 개발자가 작성한 서블릿이라는 자바 로직을 실행하여 동작합니다.

 

톰캣에 대한 내용을 다루게 된 이유는 이 톰캣과 서블릿을 왜, 어떤 장점이 있길래 많이들 사용하는지 이론이 아니라 구체적인 로직을 통해 알아보고싶었습니다.

아래 블로그가 도움이 많이 되었으니 참고해주세요.

 

 

일단은 실제 톰캣의 내부 로직은 다음장에서 자세히 분석할 예정이니, 지금은 단순히 멀티스레딩을 구현한 서버정도로 생각하고 먼저 서블릿에 대해 간단히 살펴보겠습니다.

 

 

 

Servlet

서블릿이란, 톰캣서버(서블릿 컨테이너)가 사용할 수 있도록 요청을 받고 응답을 만들어내는 로직을 정의한 단순 자바 인터페이스입니다.

이 인터페이스를 구현한 클래스를 컴파일해 서블릿 컨테이너의 특정 디렉터리에 위치시키고 특정 요청에 매핑해놓으면 해당 요청이 들어왔을 때 서블릿 컨테이너가 해당 서블릿을 실행시키는 것이죠.

이 서블릿 인터페이스는 init(), service(), destroy() 세개의 메서드를 정의하고 있고, 싱글턴 객체로 사용되도록 설계되어있어요.

 

, 서블릿을 사용하는 시스템은 요청마다 클래스를 인스턴스화하고 소멸시키는 부하가 적습니다.

예를들어 DB Connection 싱글턴 객체 생성시 connection pool 처음 한번만 초기화 하고 cp에서 꺼내쓸 있기 때문에 성능이 좋은 동적 서버를 만들 있죠.

 

 

 

Tomcat

서블릿의 싱글톤으로서의 장점을 살펴봤는데, 톰캣은 어떻게 자바 서블릿을 실행시키고 어떻게 사용자 요청을 멀티 스레딩을 통해 처리하는지 살펴보겠습니다.

톰캣은 Coyote, Jasper, Catalina라는 컴퍼넌트로 이루어져있는데

톰캣의 핵심 컴퍼넌트인  catalina를 공부해보니 톰캣이 자바 서블릿을 실행할 수 있는 이유와 어떻게 사용자 요청을 멀티 스레딩을 통해 처리하는지에 대해 알 수 있었어요.

톰캣을 실행시킨다는 것은 Catalina 서블릿 컨테이너를 실행시킨다는 것을 말합니다.

 

그리고 카타리나 서블릿 컨테이너는 java 명령어를 통해 실행할 있는 자바 애플리케이션입니다.

 

https://tomcat.apache.org/whichversion.html 에서 톰캣 소스코드를 다운받은 후 IDE 를 통해 열어 디버깅을 하며 같이 따라오시면 이해에 큰 도움이 되실겁니다.

가장 기본적으로 카타리나가 자바 애플리케이션이라는 것을 확인해 봅시다.

 

톰캣을 실행하기 위해서는 bin/startup.sh를 실행해야합니다. 

#!/bin/sh

# 
# ... 생략 ...
# 
# -----------------------------------------------------------------------------
# Start Script for the CATALINA Server
# -----------------------------------------------------------------------------
# ... 생략 ...

PRGDIR=`dirname "$PRG"`
EXECUTABLE=catalina.sh

# ... 생략 ...

exec "$PRGDIR"/"$EXECUTABLE" start "$@"

 

위 코드는 startup.sh의 일부분인데, 코드에 나와있듯 startup.sh는 바로 catalina.sh를 실행합니다.

# ... 생략 ...

eval exec "\"$_RUNJAVA\"" "\"$CATALINA_LOGGING_CONFIG\"" $LOGGING_MANAGER "$JAVA_OPTS" "$CATALINA_OPTS" \
  -D$ENDORSED_PROP="\"$JAVA_ENDORSED_DIRS\"" \
  -classpath "\"$CLASSPATH\"" \
  -Dcatalina.base="\"$CATALINA_BASE\"" \
  -Dcatalina.home="\"$CATALINA_HOME\"" \
  -Djava.io.tmpdir="\"$CATALINA_TMPDIR\"" \
  org.apache.catalina.startup.Bootstrap "$@" start
  
 # ... 생략 ...

그리고 catalina.sh를 살펴보면 이렇게 여러 vm옵션들을 추가로 하여 org.apache.catalina.startup.Bootstrap 클래스파일을 실행하는 것을 볼 수 있습니다.

Bootstrap.class를 살펴보면 당연히 main 함수를 가지고 있습니다.

public final class Bootstrap {

    /**
     * ... 생략 ...
     */

    public static void main(String[] args) {
        synchronized(daemonLock) {
            if (daemon == null) {
                Bootstrap bootstrap = new Bootstrap();

                try {
                    bootstrap.init();
                } catch (Throwable var5) {
                    handleThrowable(var5);
                    var5.printStackTrace();
                    return;
                }

                daemon = bootstrap;
            } else {
                Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
            }
        }

        try {
            String command = "start";
            if (args.length > 0) {
                command = args[args.length - 1];
            }

            if (command.equals("startd")) {
                args[args.length - 1] = "start";
                daemon.load(args);
                daemon.start();
            } else if (command.equals("stopd")) {
                args[args.length - 1] = "stop";
                daemon.stop();
            } else if (command.equals("start")) {
                daemon.setAwait(true);
                daemon.load(args);
                daemon.start();
                if (null == daemon.getServer()) {
                    System.exit(1);
                }
            } else if (command.equals("stop")) {
                daemon.stopServer(args);
            } else if (command.equals("configtest")) {
                daemon.load(args);
                if (null == daemon.getServer()) {
                    System.exit(1);
                }

                System.exit(0);
            } else {
                log.warn("Bootstrap: command \"" + command + "\" does not exist.");
            }
        } catch (Throwable var7) {
            Throwable t = var7;
            if (var7 instanceof InvocationTargetException && var7.getCause() != null) {
                t = var7.getCause();
            }

            handleThrowable(t);
            t.printStackTrace();
            System.exit(1);
        }

    }
    
    /**
     * ... 생략 ...
     */
}

톰캣을 실행한다는 것은 Bootstrap의 main 함수를 실행하는 것이라는건데, 즉 이 main함수를 실행시키는 것만으로도 톰캣 서버를 띄울 수 있습니다.

이렇게 톰캣이 그냥 자바애플리케이션이라는 것을 확인했습니다.

 

톰캣서버를 띄우는 것이 Bootstrap 앱을 실행시키는 것이라 했는데, BootStrap은 크게 세가지 단계를 거칩니다.

(디버깅을 통해 main 함수를 따라가보면 자세히 보면 init, load, start 메서드를 실행하는 것을 확인하실 수 있습니다.)

아주 간단히 각 메서드가 어떤 역할인지 먼저 설정하면

  • init은 실 로직을 담은 카타리나클래스를 인스턴스화하고
  • load는 인스턴스화된 카타리나안에서 실제 저희가 분석할 타겟인 Server 객체를 만듭니다.
  • 그리고 start 카타리나 안에 있는 Server 객체를 구동시키는 메서드라고 생각하면 됩니다.

 

 

여기까지가 전반적으로 톰캣을 훑어본 내용고, 자바 서블릿을 어떻게 실행하는지는 확인을 했으니

다음 장부터 멀티스레딩 요청처리를 어떻게 구현했는지에 초점을 맞추서 init, load, start 메서드들을 다시 자세히 살펴보겠습니다.

 

 

사업자 정보 표시펼치기/접기
1 | g | asdf | 사업자 등록번호 : 123-12-12345 | TEL : 010-111-1111 | Mail : asdf@gmail.com | 통신판매신고번호 : 호 | 사이버몰의 이용약관 바로가기