메뉴 바로가기 검색 및 카테고리 바로가기 본문 바로가기

한빛출판네트워크

한빛랩스 - 지식에 가능성을 머지하다 / 강의 콘텐츠 무료로 수강하시고 피드백을 남겨주세요. ▶︎

IT/모바일

톰캣 사용하기 IV - 자바 애플리케이션에 톰캣 임베딩하기

한빛미디어

|

2002-06-11

|

by HANBIT

13,289

저자: 제임스 굿윌(James Goodwill), 역 이상훈

본 기사에서는 Tomcat JSP/servlet 컨테이너의 임베디드 버전을 다루는 자바 애플리케이션을 제작해볼 것이다. 이로써 우리는 Tomcat을 애플리게이션 레벨까지 확장시켜서 살펴볼 수 있을 것이다. Tomcat은 각각 고유한 목적을 지닌 컨테이너의 집합으로 분해해볼 수 있으며 이러한 컨테이너들은 기본적으로 server.xml 파일을 이용해서 설정된다. 그렇지만 임베딩할 때는 이 설정파일을 사용할 수 없기 때문에 이러한 컨테이너들의 인스턴스를 프로그램적으로 조합해야 한다. 아래에 보이는 XML 코드 부분은 Tomcat 컨테이너들의 계층구조를 포함하고 있다.

  
    
    
      
        
      
    
  


주: 앞서 나열된 각각의 요소들은 적절한 동작을 설정하는 속성을 포함하고 있다. 그렇지만 본 기사의 목적을 위해서는 요소의 계층구조와 관계만이 중요하다고 본다.
위에서 보는 구조가 바로 임베디드 애플리케이션을 작성하기 위해 필요한 구조이다. 이 구조에서 요소들은 무조건적으로 생성될 것이기 때문에 굳이 이 오브젝트들을 생성해야 할 필요는 없다. 컨테이너 구조의 나머지 부분을 작성하는 단계는 다음과 같다.

Tomcat 컨테이너의 임베디드 버전을 작성하기 위해서는 아래의 단계들을 반드시 수행해야만 한다.
  1. org.apache.catalina.Engine 인스턴스를 생성한다. 이 오브젝트는 위의 요소를 나타내고 요소에 대한 컨테이너로 작동한다.

  2. 가상호스트를 나타내는 org.apache.catalina.Host 오브젝트를 생성하고 이 인스턴스를 오브젝트에 추가한다.

  3. 이제 이 Host에서 각각의 웹 애플리케이션을 표현할 n개의 org.apache.catalina.Context 오브젝트를 생성한다.

  4. 일단 각각의 Context들이 생성되었으면, 생성된 각각의 Context들을 이전에 생성했던 Host에 추가해야 한다. 여기에서는 onjava 애플리케이션을 나타낼 단일 Context를 생성할 것이다.

  5. 마지막 단계로 org.apache.catalina.Connector 오브젝트를 생성하고 이것을 이전에 생성했던 Engine과 조합한다. 이 Connector 오브젝트는 클라이언트의 요청에 대해 실제로 응답하는 오브젝트이다.
이와 같은 애플리케이션을 생성하기 위해 우리는 기존의 Tomcat 클래스들을 투입할 것이다. 여기서 투입되는 Tomcat 클래스는 이러한 형태의 통합을 쉽게 개발하기 위해 작성되었다. 그리고 여기서 사용하게 될 메인 클래스는 /src/catalina/src/share/org/apache/catalina/startup 디렉토리에 있는 org.apache.catalina.startup.Embedded 클래스로 아래에 보이는 소스리스트는 org.apache.catalina.startup.Embedded 클래스를 사용하는 이러한 컨테이너들을 작성하는 예제 애플리케이션을 담고 있다.
package onjava;

import java.net.URL;
import org.apache.catalina.Connector;
import org.apache.catalina.Context;
import org.apache.catalina.Deployer;
import org.apache.catalina.Engine;
import org.apache.catalina.Host;
import org.apache.catalina.logger.SystemOutLogger;
import org.apache.catalina.startup.Embedded;
import org.apache.catalina.Container;

public class EmbeddedTomcat {

  private String path = null;
  private Embedded embedded = null;
  private Host host = null;
  /**
    * Default Constructor 
    *
    */
  public EmbeddedTomcat() {

  }

  /**
    * Basic Accessor setting the value of the context path
    *
    * @param path - the path
    */
  public void setPath(String path) {

    this.path = path;
  }

  /**
    * Basic Accessor returning the value of the context path
    *
    * @return - the context path
    */
  public String getPath() {

    return path;
  }

  /**
    * This method Starts the Tomcat server.
    */
  public void startTomcat() throws Exception {

    Engine engine = null;
    // Set the home directory
    System.setProperty("catalina.home", getPath());

    // Create an embedded server
    embedded = new Embedded();
    // print all log statments to standard error
    embedded.setDebug(0);
    embedded.setLogger(new SystemOutLogger());

    // Create an engine
    engine = embedded.createEngine();
    engine.setDefaultHost("localhost");

    // Create a default virtual host
    host = embedded.createHost("localhost", getPath()
      + "/webapps");
    engine.addChild(host);

    // Create the ROOT context
    Context context = embedded.createContext("",
      getPath() + "/webapps/ROOT");
    host.addChild(context);

    // Install the assembled container hierarchy
    embedded.addEngine(engine);

    // Assemble and install a default HTTP connector
    Connector connector =
      embedded.createConnector(null, 8080, false);
    embedded.addConnector(connector);
    // Start the embedded server
    embedded.start();
  }

  /**
    * This method Stops the Tomcat server.
    */
  public void stopTomcat() throws Exception {
    // Stop the embedded server
    embedded.stop();
  }

  /**
    * Registers a WAR with the container.
    *
    * @param contextPath - the context path under which the
    *               application will be registered
    * @param warFile - the URL of the WAR to be
    * registered.
    */
  public void registerWAR(String contextPath, URL warFile)
    throws Exception {

    if ( contextPath == null ) {

      throw new Exception("Invalid Path : " + contextPath);
    }
    if( contextPath.equals("/") ) {

      contextPath = "";
    }
    if ( warFile == null ) {

      throw new Exception("Invalid WAR : " + warFile);
    }

    Deployer deployer = (Deployer)host;
    Context context = deployer.findDeployedApp(contextPath);

    if (context != null) {

      throw new
        Exception("Context " + contextPath
        + " Already Exists!");
    }
    deployer.install(contextPath, warFile);
  }

  /**
    * Unregisters a WAR from the web server.
    *
    * @param contextPath - the context path to be removed
    */
  public void unregisterWAR(String contextPath)
    throws   Exception {

    Context context = host.map(contextPath);
    if ( context != null ) {

      embedded.removeContext(context);
    }
    else {

      throw new
        Exception("Context does not exist for named path : 
        + contextPath);
    }
  }

  public static void main(String args[]) {

    try {

      EmbeddedTomcat tomcat = new EmbeddedTomcat();
      tomcat.setPath("d:/jakarta-tomcat-4.0.1");
      tomcat.startTomcat();

      URL url =
        new URL("file:D:/jakarta-tomcat-4.0.1"
        + "/webapps/onjava");
      tomcat.registerWAR("/onjava", url);

      Thread.sleep(1000000);

      tomcat.stopTomcat();

      System.exit(0);
    }
    catch( Exception e ) {

      e.printStackTrace();
    }
  }
}
EmbeddedTomcat 애플리케이션 소스는 main() 메소드부터 검토를 시작해야 한다. 이 메소드는 처음에 EmbeddedTomcat 클래스의 인스턴스를 생성한다. 다음에 Tomcat 인스턴스를 서비스할 Tomcat이 설치된 패스를 설정한다. 이 패스는 환경변수와 동일하다. main() 메소드의 다음 작업은 startTomcat() 메소드를 호출(invoke)하는 것이다. 이것은 앞서 기술했던 컨테이너 구축 단계를 수행하는 메소드이다. 이 메소드에서 구현단계는 아래와 같다.
  1. main() 메소드는 시스템 프로퍼티를 패스 속성값으로 설정하는 것으로 시작한다.
    // 홈디렉토리를 지정한다.
    System.setProperty("catalina.home", getPath());
    

    주 의: setPath() 메소드에 넘겨줬던 디렉토리 값과 같은 변수를 에 사용해야 한다.
  2. 이 메소드의 다음 구현단계는 Embedded 오브젝트의 인스턴스를 생성하고 현재 로거(logger)에 디버그 레벨을 설정한다.
       // 임베디드 서버를 생성
       embedded = new Embedded();
       embedded.setDebug(5);
       // 표준 오류에 대한 모든 로그 문장 출력
       embedded.setLogger(new SystemOutLogger());
    

    주 의: 웹 애플리케이션 제품을 실제 배치할 때, 디버그 레벨은 0이어야 함에 주의하자. 디버그 레벨을 0으로 하는 것은 성능향상에 지대한 영향을 미치는 Tomcat이 수행할 로그 기록량을 감소시킨다.
  3. 애플리케이션이 Embedded 오브젝트의 인스턴스를 가지고 나면 org.apache.catalina.Engine 클래스의 인스턴스를 생성하고 기본 호스트 이름을 설정한다. Engine 객체는 전 Catalina 서블릿 컨테이너를 표현한다.
       // 엔진을 생성
       engine = embedded.createEngine();
       engine.setDefaultHost("localhost");
    
  4. Engine 이 초기화 되고 나면 /webapps/ 디렉토리를 지시하는 패스로 localhost라고 명명된 org.apache.catalina.Host 오브젝트를 만들고 Engine 오브젝트에 추가한다. Host 오브젝트는 Catalina Engine의 각 인스턴스에 저장되는 가상호스트를 정의한다.
       // 기본 가상 호스트 생성
       host = embedded.createHost("localhost", getPath() +
         "/webapps");
    
       engine.addChild(host);
    
  5. startTomcat() 메소드가 수행하는 다음 단계는 Tomcat과 패키지 되어있는 ROOT 웹 애플리케이션을 나타내는 org.apache.catalina.Context 오브젝트를 만들고, 기존에 생성되었던 Host에 추가하는 것이다. ROOT 웹 애플리케이션은 기본적으로 설치되는 유일한 애플리케이션이다.
    // Create the ROOT context
      Context context = embedded.createContext("",
        getPath() + "/webapps/ROOT");
    host.addChild(context);
    
  6. 다음 단계는 생성된 ROOT와 Context를 담고 있는 Engine을 Embedded 오브젝트에 추가하는 것이다.
    // 조합된 컨테이너 계층구조 설치
    embedded.addEngine(engine);
    
  7. engine이 오브젝트에 추가되고 나면 startTomcat() 메소드는 org.apache.catalina.Connector 오브젝트를 만들고 이전에 생성된 Engine 과 조합한다. 요소는 클라이언트 애플리케이션에서 요청된 요구와 응답을 실제로 처리하는 클래스를 정의한다. 조금 뒤에 나올 8080포트로 서비스될 HTTP 커넥터가 생성되고 Embedded 오브젝트에 추가될 것이다.
    // Assemble and install a default HTTP connector
      Connector connector = embedded.createConnector(null,
        8080, false);
    embedded.addConnector(connector);
    
  8. startTomcat() 메소드의 마지막 수행단계는 Tomcat 컨테이너를 시작하는 것이다.
    embedded.start();
    
startTomcat()이 수행되고 나면 메인 메소드는 이미 배치된 registerWAR() 메소드를 호출한다. 그리고 이 메소드는 이전에 배치된 onjava 애플리케이션을 Embedded 오브젝트에 설치한다. 이 예제에 사용된 URL은 자바 서블릿 2.2와 이후 버전의 스펙을 따르는 어떤 Webapp 디렉토리도 지시할 수 있다.
URL url =
    new URL("file:D:/jakarta-tomcat-4.0.1"
    + "/webapps/onjava");
tomcat.registerWAR("/onjava", url);
그리고 나면 주 애플리케이션은 서비스 요청이 들어올 때까지 임베디드 서버를 대기하도록 한다. 애플리케이션이 요청되면 임베디드 서버는 작업을 중지하고 애플리케이션을 빠져 나온다.

이 애플리케이션을 시험하기 위해서 다음 단계를 완수해야 한다.
  1. EmbeddedTomcat.java 클래스를 컴파일 한다
  2. Tomcat의 모든 다른 인스턴스들이 중지해있음을 확인한다
  3. Tomcat 설치중에 볼 수 있는 다음의 jar 파일을 애플리케이션 클래스 패스에 추가한다
    • /bin/bootstrap.jar
    • /server/lib/catalina.jar
    • /server/lib/servlet-cgi.jar
    • /server/lib/servlets-common.jar
    • /server/lib/servlets-default.jar
    • /server/lib/servlets-invoker.jar
    • /server/lib/servlets-manager.jar
    • /server/lib/servlets-snoop.jar
    • /server/lib/servlets-ssi.jar
    • /server/lib/servlets-webdav.jar
    • /server/lib/jakarta-regexp-1.2.jar
    • /lib/naming-factory.jar
    • /common/lib/crimson.jar
    • /common/lib/jasper-compiler.jar
    • /common/lib/jasper-runtime.jar
    • /common/lib/jaxp.jar
    • /common/lib/jndi.jar
    • /common/lib/naming-common.jar
    • /common/lib/naming-resources.jar
    • /common/lib/servlet.jar
    • /common/lib/tools.jar
  4. 컴파일된 EmbeddedTomcat 클래스를 담고있는 디렉토리가 클래스패스에 포함되어있음을 확인한다
  5. 다음 명령을 실행한다
    java onjava.EmbeddedTomcat
    
만약 모든 것이 계획대로 되었다면 콘솔창에 로그 문장을 보게 될 것이다.
  HttpProcessor[8080][0] Starting background thread
  HttpProcessor[8080][0]  Background thread has been started
  HttpProcessor[8080][1] Starting background thread
  HttpProcessor[8080][1]  Background thread has been started
  HttpProcessor[8080][2] Starting background thread
  HttpProcessor[8080][2]  Background thread has been started
  HttpProcessor[8080][3] Starting background thread
  HttpProcessor[8080][3]  Background thread has been started
  HttpProcessor[8080][4] Starting background thread
  HttpProcessor[8080][4]  Background thread has been started
일단 앞의 문장을 보았다면 아래 URL을 사용하여 ROOT/onjava 웹 애플리케이션에 접근할 수 있을 것이다.
  • http://localhost:8080/
  • http://localhost:8080/onjava/
제임스 굿윌(James Goodwill)은 콜로라도 주 덴버에 있는 Virtuas Solutions, LLC사의 수석 설계자이자 공동 창립자이다.
TAG :
댓글 입력
자료실

최근 본 상품0