톰캣의 컴포넌트 포함관계는 위의 그림과 같다.

  Bootstrap > Server > Service > Connector , Engine > Host > Context  > Loader, Wrapper


  1. 서버 

     -  카탈리나 서블릿 컨테이너 전체를 나타냄 + 다른 모든 컴포넌트를 포함.

     -  전체 시스템을 시작하고 종료할수 있다.

     -  server.xml 파일과 연관되있다.

     -  start() 메소드에서는 , 모든 서비스들을 시작한다. (http://dbdb.tistory.com/3)

     -  await() 함수안에서 8085 포트로 생성한 서버소켓에 시스템 종료 메세지기 올때까지 기다린다.


 2. 서비스

     - 1개의 컨테이너나 1개 이상의 커넥터등의 컴포넌트를 포함한다.

     - 여러개의 커넥터를 가짐으로서 톰캣은 여러 프로토콜(http, https)에 대해 서비스하는것이 가능해진다.

     - 서비스와 연결된 컨테이너는 각 커넥터의 setContainer 메소드에 전달되어 서로 연결된다.

 3. 엔진 

     - 컨테이너 인터페이스를 상속받는다. (최상위 컨테이너 역할을 한다)

     - 카탈리나 서블릿 엔진 전체를 나타낸다.

     - 여러개의 가상 호스트를 지원하고 싶다면 엔진을 사용해야 할것이다.(http://dbdb.tistory.com/4)

     - 엔진이 사용되면 엔진은 항상 최상위의 컨테이너가 된다. 

     - 엔진에 추가되는 하위 컨테이너는 보통 Host 나 Context 를 구현한 컨테이너이다. 

     - 기본적으로 톰캣 배포본에서는 엔진이 사용되며, 엔진은 하나의 기본 호스트를 갖는다.


 4. 호스트

     - 컨테이너 인터페이스를 상속받는다.

     - 최상위 컨테이너로 호스트를 사용할수도 있다. (엔진을 사용하면 호스트가 차일드)

     - 각 컨텍스트가 ContextConfig 를 사용하도록 설정 되 있다면 반드시 호스트가 존재한다.

     - 컨텍스트의 상위 컨테이너는 일반적으로 호스트이지만, 다른 컨테이너의 구현을 사용하거나 

       필요없다면 생략될 수도 있다. (실제 상황에서는 톰캣은 항상 호스트를 필요로한다) 

 

5. 컨텍스트 

    - Context 인터페이스를 상속받는다. (StandardContext 가 구현체) 

    - 하나의 웹 어플리케이션을 나타내며 1개 이상의 래퍼를 포함한다.

    - 로더와 매니저를 필요로한다.

    - start() 메소드가 호출되야한다.

    - %CATALINA_HOME%/conf 디렉토리에 있는 기본 web.xml 내용을 파싱해, 배치돼있는 모든 

      애플리케이션에 적용할수 있도록 준비한다.

    - 각 애플리케이션수준의 web.xml 을 처리한다. 

    - 각종 밸브 (인증자, 증명등)를 처리한다.

      * start() 메소드에서 하는일 

          가. BEFORE_START_EVENT 이벤트 발생 

          나. available 특성의 값을 false 로 지정

          다. configured 특성의 값을 false 로 지정

          라. 자원준비

          마. 로더 준비

          바. 매니저 준비

          사. 문자셋 맵퍼 초기화

          아. 이 컨텍스트와 연관된 다른 컴포넌트 구동

          자. 하위 컨테이너(래퍼) 구동

          차. 파이프라인 구동

          카. 매니저 구동

          파. START_EVENT 이벤트 발생 (리스너 (ContextConfig) 는 몇가지 설정 작업을 수행)

          타. configured 값 확인

          하. AFTER_START_EVENT 이벤트 발생 



6. 로더

   - 컨텍스트마다 하나의 클래스 로더가 존재한다. 따라서 컨텍스트끼리 클래스 공유는 안된다.


7. 래퍼 

   - 하나의 서블릿을 래핑한다.   




시작 소스 예제 

public final class Bootstrap {

  public static void main(String[] args) {


    System.setProperty("catalina.base", System.getProperty("user.dir"));

    Connector connector = new HttpConnector();


    Wrapper wrapper1 = new StandardWrapper();

    wrapper1.setName("Primitive");

    wrapper1.setServletClass("PrimitiveServlet");

    Wrapper wrapper2 = new StandardWrapper();

    wrapper2.setName("Modern");

    wrapper2.setServletClass("ModernServlet");


    Context context = new StandardContext();

    // StandardContext's start method adds a default mapper

    context.setPath("/app1");

    context.setDocBase("app1");


    context.addChild(wrapper1);

    context.addChild(wrapper2);


    LifecycleListener listener = new SimpleContextConfig();

    ((Lifecycle) context).addLifecycleListener(listener);


    Host host = new StandardHost();

    host.addChild(context);

    host.setName("localhost");

    host.setAppBase("webapps");


    Loader loader = new WebappLoader();

    context.setLoader(loader);

    // context.addServletMapping(pattern, name);

    context.addServletMapping("/Primitive", "Primitive");

    context.addServletMapping("/Modern", "Modern");


    Engine engine = new StandardEngine();

    engine.addChild(host);

    engine.setDefaultHost("localhost");


    Service service = new StandardService();

    service.setName("Stand-alone Service");

    Server server = new StandardServer();

    server.addService(service);

    service.addConnector(connector);


    //StandardService class's setContainer will call all its connector's setContainer method

    service.setContainer(engine);


    // Start the new server

    if (server instanceof Lifecycle) {

      try {

        server.initialize();

        ((Lifecycle) server).start();

        server.await();

        // the program waits until the await method returns,

        // i.e. until a shutdown command is received.

      }

      catch (LifecycleException e) {

        e.printStackTrace(System.out);

      }

    }


    // Shut down the server

    if (server instanceof Lifecycle) {

      try {

        ((Lifecycle) server).stop();

      }

      catch (LifecycleException e) {

        e.printStackTrace(System.out);

      }

    }

  }

}

리눅스에서 애플리케이션 시작하기

java -classpath ./lib/servelt.jar:./lib/commons-collections.jar:./commons-digester.jar:./libnaming-factory.jar:./lib/naming-common.jar:./lib/tomcat-util.jar:./  ex14.pyrmont.startup.Bootstrap


중지하기

java ex14.pyrmont.startup.Stopper


서블릿 호출하기

http://localhost:8080/app1/Primitive


'WAS & 웹서버' 카테고리의 다른 글

톰캣 최종분석 ex05 소스 분석  (0) 2015.08.15
톰캣 클래스패스의 이해 (번역)  (0) 2015.07.31




1. main 으로 시작한다.  (크게 2개의 컴포넌트(?) 로 나누어진다. HTTPConnector 와 SimpleContext) 


2. main 은 각각의 클래스들의 객체를 생성하고 의존관계를 맺은 후에  HttpConnector 의 start 를 호출하여 

  솔루션이 시작된다.


3. 크게 2가지 파이프라이닝이 있다. ( 파이프라인에 대한건 chain of responsibility 패턴이나 ,  intercepting 

   filter 패턴을 알면 이해하기 쉽다) . 이걸 이해해야한다. 


4. SimplePipiline 은 intercepting filter 패턴에서 매니저 역할이다. 이것은 각각의 valve (filter 와 같다) 를 순

  회하며 각각의 선행작업을 한후에 마지막에 basic 작업을 하며 종료한다. 마치 필터들이 선행해서 어떤 액션

  을 한후에 마지막에 컨트롤러가 마무리하는것과 같다. 


5. SimpleLoader 는 서블릿 클래스를 메모리로 올리는 유틸리티성 클래스이다.


6. HTTPConnector 는 젤 앞에서 서버소켓을 운용하며, 클라이언트과 커낵션을 맺고, request/ response 객

  체를 생성하여 SimpleContext 객체에 invoke 한다. 


7. SimpelContextMapper 는 내부의 맵을 이용하여 url 에 맞는 서블릿을 리턴해준다. 


8. SimpleWrapper A 는 A 서블릿의 래퍼이다. 


9. 중요한 2가지 파이프라이닝에 대해서 알아보자.


10. 첫번째 파이프라이닝은 SimpleContext 가 가지고있는데 , 해당 파이프라이닝은  value 로써

    ClientIPLoggerValve 와 HeaderLogerValue 를 가지고있으면 마지막 basic 은 SimpleContextValve 를 호

    출하며 끝마친다. 

    예상하듯이 앞의 두 밸브는 필터역할을 하며, 마지막 SimpleContextValve  는 클라이언트가 요청하는 서

    블릿을 찾아내어 해당 서블릿의 파이프라이닝을 시작한다.


11. 두번째 파이프라이닝은 SimpelWrapper A 에 등록된 valve 를 따라가며 진행되는데, 이 예제에서는 선행 

     valve  는 없으며 마지막 basic 이  SimpleWrapperValve 이다. 

     SimpleWrapperValve  의 역할은 클라이언트가 요청한 서블릿의 service 메소드를 호출하는것이다.


     결국 우리가 어떤 서블릿(컨트롤러) 를 만들어서 톰캣이나 스프링에 설정해두면, SimpleWrapperValve 

     이 해당 컨트롤러를 호출하게되는것이다.


아래 코드는 SimpleWrapperValve  의 invoke 함수이다. 


public void invoke(Request request, Response response, ValveContext valveContext)

    throws IOException, ServletException {


    SimpleWrapper wrapper = (SimpleWrapper) getContainer();

    ServletRequest sreq = request.getRequest();

    ServletResponse sres = response.getResponse();

    Servlet servlet = null;

    HttpServletRequest hreq = null;

    if (sreq instanceof HttpServletRequest)

      hreq = (HttpServletRequest) sreq;

    HttpServletResponse hres = null;

    if (sres instanceof HttpServletResponse)

      hres = (HttpServletResponse) sres;


    // Allocate a servlet instance to process this request

    try {

      servlet = wrapper.allocate();

      if (hres!=null && hreq!=null) {

        servlet.service(hreq, hres);

      }

      else {

        servlet.service(sreq, sres);

      }

    }

    catch (ServletException e) {

    }

  }


'WAS & 웹서버' 카테고리의 다른 글

톰캣 최종분석 ex14 소스 분석  (0) 2015.08.24
톰캣 클래스패스의 이해 (번역)  (0) 2015.07.31


톰캣의 클래스패스 (웹어플리케이션이 필요로하는 JAR 파일을 찾는) 를 어떻게 설정하는지에 관한 문제는 

어느 게시판을 가더라도 많은 흔한 주제이다.


왜 톰캣 유저에게 클래스패스가 문제를 일으키나? 


classpath  는 JVM 에게 해당 어플리케이션을 동작시키기 위해 클래스/패키지를 어디서 찾으라고 알려주는 인자이다. 

근데 왜  저런 클래스 패스를 잘 알고있는 경험많은 자바 개발자들이 톰캣에서는 문제를 가질까? 

그것에 대한 3가지 답변이 있다.

  1. Tomcat 는 다른 자바프로그램과 동일한 방법으로 classpath 를 바라보지 않는다.
  2. Tomcat 이 classpath 를 해결하는 방법은 매 버전마다 조금씩 달라져 왔다.
  3. 톰캣의 기술문서와 기본 설정은 어떤것을 이루어내는 가장 좋은 방법을 푸쉬하는데, 만약 이 가장좋은 방법을 
    따르지 않는다면 , 어둠속에서 배회하게 될것이며  만약 니가 다른 이상한 짓을 한다면 , 별다른 정보를 제공받지 못할것이다.
    (바깥에 있는 디펜던시 , 공유되는 디펜던시  or  동일한 라이브러리/클래스의 다중 버전 같은..) 


일반적인 사용법과 달리 어떻게 톰캣 클래스 패스는 사용되는가?

모든 아파치 톰캣은 가능한 자동적이면서,  직관적이며,  자기-포함 (self-contained) 이라는 목적을 갖고있는데 효율적인 관리를 위해 웹 어플리케이션의 배포나 설정을 표준화하려고 노력중이다. 그와 동시에 보안과 네임스페이스 이유에 대한 여러 라이브러리들의 접근을 제한하고 있다. (?)

자바 클래스 패스 환경 변수를 사용하는것보다 어려운 이유는 , 톰캣의 "시스템" 클래스로더를 만들어질때  톰캣의 스타트 스크립트는 이런 변수(OS환경변수) 를 무시하며,자신의 클래스패스를 만들어버린다.  

Tomcat 이 어떻게  classpath 를 설정하는지 이해하기위해  Tomcat 6 의 시작 프로세스를 살펴보자.

  1. JVM 부트스트랩 로더는 코어 자바 라이브러리를 로딩한다. JAVA_HOME  변수를 통해서 코어라이브러리의 위치를 알수있다.

  2. Startup.sh 은 "start"  파라미터와 함께  bin/Catalina.sh 를 호출하며 , 시스템 클래스 패스를 덮어쓰고  bootstrap.jar  과 tomcat-juli.jar. 를 로딩한다.  이 리소스들은 오직 Tomcat 한테만 보인다.

  3. 클래스로더들은 각각 디플로이된 컨텍스트에 대해 생성되며  그것들은 웹 어플리케이션 마다의   WEB-INF/classes 와 WEB-INF/lib  안에 있는 JAR 와 클래스들을 로드한다. 이런 리소스들은 오직 그들을 로드한 웹어플리케이션에만 보인다.
     
  4. Common 클래스로더는  $CATALINA_HOME/lib 에 있는 모든 클래스들과 JAR 를 로드한다.  이 리소스들은 톰켓과 모든 어플리케이션에 노출된다.

톰캣은 4개 혹은 그 이상의 속성에 의해 설정된 여러가지 클래스패스들을 해석하는데,  그것중에 

하나만 표준위치에 있을뿐이다.톰캣에 공통 라이브러리를 추가하려면  TOMCAT_HOME/bin/catalina.sh 

파일에  CLASSPATH를 추가해주거나 TOMCAT_HOME/conf/catalina.properties  에 common.loader를 추

가해 주면 된다.


레퍼런스 : https://www.mulesoft.com/tcat/tomcat-classpath


'WAS & 웹서버' 카테고리의 다른 글

톰캣 최종분석 ex14 소스 분석  (0) 2015.08.24
톰캣 최종분석 ex05 소스 분석  (0) 2015.08.15

+ Recent posts