제1장 애플리케이션

내용 목차

1.1. 모듈과 애플리케이션
1.1.1. 모듈
1.1.2. 애플리케이션
1.2. 공유 라이브러리(Shared Library)
1.2.1. 개요
1.2.2. 라이브러리 Deploy 및 설정
1.2.3. 애플리케이션에서 라이브러리 참조하기
1.2.4. 클래스 로딩 방식
1.2.5. Version Ordering Rule

본 장에서는 실제로 모듈과 애플리케이션이 어떻게 구성되어 있으며, 각각의 구성 요소에는 무엇이 있는지에 대해 설명한다. 또한 이러한 구성 요소들의 JEUS에서의 구조와 설정 방법, 이렇게 작성된 애플리케이션을 디플로이하기 위해 JEUS에서 제공하는 기능에 대해 설명한다.

1.1. 모듈과 애플리케이션

Java EE 애플리케이션은 하나 이상의 모듈로 구성되어 있다. Java EE 모듈은 하나 이상의 동일한 타입인 Java EE 컴포넌트(EJB, 웹 애플리케이션, 애플리케이션 클라이언트, connector)와 Deployment Descriptor(DD)들로 구성된다. DD는 Java EE 표준 DD(application.xml 등)와 JEUS DD(jeus-application-dd.xml 등)가 있으며, Java EE 5 이후에서는 표준 DD 없이도 대부분의 설정을 클래스에 Annotation으로 대체할 수 있다.

다음은 Java EE 모듈 및 애플리케이션 구성이다.

[그림 1.1] Java EE 모듈 및 애플리케이션 구성

Java EE 모듈 및 애플리케이션 구성


1.1.1. 모듈

Java EE 모듈에는 다음의 4종류가 있다.

  • EJB 모듈 (.jar file)

    EJB(Enterprise JavaBeans)는 트랜잭션 및 보안 서비스를 이용하는 비즈니스 로직을 구현하기 위한 표준 서버 측 컴포넌트 모델이다. EJB 모듈은 이러한 EJB들을 표현하고 그룹화하기 위한 개념으로 JEUS에서는 JEUS EJB 엔진에 배치할 수 있는 가장 작은 단위를 의미한다.

    따라서 1개의 EJB가 배치되어도 반드시 EJB 모듈로 패키지화(.jar file) 되어야 한다. EJB 모듈의 자세한 내용은 "JEUS EJB 안내서"를 참고한다.

  • 웹 애플리케이션(Web application) 모듈 (.war file)

    웹 애플리케이션(Web Application) 모듈은 클라이언트의 요청에 의한 웹 기반의 서비스(예를 들면, 장바구니에 물품을 추가하거나, 장바구니 안의 물품을 구매하거나 웹 기반의 경매 사이트에서 물건을 사기 위해 브라우징 하는 등)를 실행하기 위한 정적 콘텐츠(static content)와 동적 콘텐츠(dynamic content)의 집합이라고 할 수 있다.

    웹 애플리케이션 모듈에 대한 자세한 내용은 "JEUS Web Container 안내서"를 참고한다.

  • 애플리케이션 클라이언트(Application client) 모듈 (.jar file)

    애플리케이션 클라이언트(Application Client)는 별도의 JVM에서 실행되는 클라이언트 프로그램이다. 애플리케이션 클라이언트는 main() 메소드를 호출해서 실행하고, 가상 머신이 종료되면 실행을 마친다.

    다른 Java EE 애플리케이션 컴포넌트처럼 애플리케이션 클라이언트는 시스템 서비스를 제공하는 클라이언트 컨테이너(Client Container)에서 동작한다. 클라이언트 컨테이너는 다른 Java EE 컨테이너에 비해서 매우 적은 양의 시스템 리소스를 사용한다.

    애플리케이션 클라이언트 모듈에 대한 자세한 내용은 "JEUS Application Client 안내서"를 참고한다.

  • 리소스 어댑터(Resource adapter) 모듈 (.rar file)

    리소스 어댑터(Resource Adapter)는 Java EE 커넥터 아키텍처의 중심 컴포넌트로 특정 EIS(Enterprise Information System)용으로 개발되어서 EIS와 상호작용하기 위한 API를 제공한다. 또한 Java EE 애플리케이션 서버와 연동하기 위한 시스템 API도 제공한다. 관리자의 관점에서는 모든 작업이 리소스 어댑터의 설정과 배치만으로 종료된다.

    리소스 어댑터 모듈에 대한 자세한 내용은 "JEUS JCA 안내서"를 참고한다.

1.1.2. 애플리케이션

[그림 1.1]을 보면 Java EE 애플리케이션은 하나 이상의 Java EE 모듈과 2개의 DD로 구성된다. DD는 Java EE DD(application.xml)와 JEUS DD(jeus-application-dd.xml)로 구성된다. 이때 Java EE 모듈은 1개 이상의 동일한 타입인 컴포넌트들과 DD들로 구성되기 때문에 하나의 컴포넌트만으로도 애플리케이션을 만들 수 있다.

Java EE 애플리케이션은 확장자가 .ear인 일반적인 JAR Archive 형식의 파일로 다음은 EAR 구성의 간단한 예이다. EAR 파일의 루트 디렉터리에는 애플리케이션에 포함된 각 모듈 Archive 파일들과 APP-INF, META-INF 디렉터리가 존재한다.

[그림 1.2] .ear archive의 구성

.ear archive의 구성


다음은 각 디렉터리에 대한 설명이다.

APP-INF

APP-INF 디렉터리는 공통 라이브러리 디렉터리로 웹 애플리케이션 모듈의 WEB-INF 디렉터리와 비슷한 기능을 제공한다. WEB-INF와 마찬가지로 APP-INF 또한 하위에 classes와 lib 디렉터리를 가지고 있으며, 각각 클래스 파일과 .jar 파일을 포함한다. 이렇게 APP-INF 아래에 존재하는 classes의 클래스들과 lib의 JAR 파일들은 이 애플리케이션에서 라이브러리로 사용할 수 있다(모든 하위 모듈에서 자동으로 classpath로 인식한다).

또한, Java EE 5에서부터는 JEUS에서 제공하는 APP-INF\lib와 유사한 라이브러리 디렉터리를 지원하는데, 이는 application.xml에 <library-directory> 태그로 설정하여 사용할 수 있다. 만약 application.xml에 <library-directory> 태그를 사용하지 않거나 application.xml 자체가 없는 경우에는 디폴트로 lib라는 이름의 디렉터리를 사용한다.

주의

라이브러리 디렉터리는 표준이므로 JEUS 6 이후에서는 APP-INF 디렉터리보다는 라이브러리 디렉터리를 사용할 것을 권장한다.

META-INF

META-INF 디렉터리에는 2개의 DD가 존재한다. Java EE DD인 application.xml과 JEUS DD인 jeus-application-dd.xml이며, 이 파일들은 없어도 무방하다.

1.2. 공유 라이브러리(Shared Library)

본 절에서는 애플리케이션 간에 공유되는 라이브러리(Shared Library)를 추가하고, 사용하는 기능에 대해 설명한다.

1.2.1. 개요

공유 라이브러리(Shared Library)는 애플리케이션 간에 공유되는 라이브러리로 JEUS 시스템(JEUS_HOME/lib/system) 또는 애플리케이션(JEUS_HOME/lib/application) 디렉터리에 추가되는 시스템 라이브러리와는 구별된다.

공유 라이브러리(SharedLibrary)는 JEUS 전체 시스템에 영향을 주지 않고 각 애플리케이션에서 해당 라이브러리를 사용할 것인지 여부를 설정할 수 있으며, JEUS 재기동 없이 동적으로 추가할 수도 있고, 같은 라이브러리를 여러 개의 버전으로 설치하여 선택적으로 사용할 수 있다.

공유 라이브러리는 다음과 같은 특징을 가진다.

  • 라이브러리 파일이 애플리케이션 간에 공유될 수 있고 따라서 사용자가 항상 함께 패키징(packaging)하지 않아도 된다.

  • 라이브러리는 JEUS가 구동 중에도 동적으로 추가/삭제될 수 있다.

  • 새로운 버전으로 라이브러리를 추가하고 애플리케이션을 Redeploy해서 업그레이드된 라이브러리를 사용할 수 있다.

  • 해당 라이브러리의 여러 버전의 구현체를 등록할 수 있고, 어떤 구현체를 사용할지는 Deployment Time에 결정할 수 있다.

각 라이브러리는 2개의 버전(specification, implementation)을 가질 수 있다. 이렇게 함으로써 사용자들은 같은 라이브러리의 여러 개의 버전을 설치할 수 있고, 애플리케이션이 필요한 버전을(highest, minimum or exact) Deployment Time에 동적으로 선택하게 한다.

추후에 여러 버전의 라이브러리를 지원하기 위해서는 처음부터 항상 버전을 설정하는 것을 권장하며, 단순한 use case를 위해서는 버전을 전혀 사용하지 않아도 무방하다. 버전이 설정되지 않았다면 기본적으로 0라는 버전 값으로 내부적으로 해석한다.

1.2.2. 라이브러리 Deploy 및 설정

하나의 라이브러리는 여러 개의 JAR 파일로 구성될 수 있는데 이는 보통 공유 라이브러리 디렉터리인 JEUS_HOME/lib/shared 하위에 위치한다. 그리고 JAR 파일들은 JEUS_HOME/lib/shared/libraries.xml 설정 파일에 라이브러리로 등록한다.

다음 예에서 'myLibrary'는 2.0 스펙을 구현하는 2.1 버전의 구현체로 정의하여 등록되었다. 이 라이브러리는 여러 개의 JAR 파일(commons-logging.jar, commons-util.jar, 그리고 myLib -2.1 서브 디렉터리에 있는 모든 JAR 파일)로 구성되어 있다.

[예 1.1] 공유 라이브러리 등록 : <<libraries.xml>>

<library>
     <library-name>myLibrary</library-name>
     <specification-version>2.0</specification-version>
     <implementation-version>2.1</implementation-version>
     <files dir=".">
         <include name="commons-logging.jar"/>
         <include name="commons-util.jar"/>
     </files>
     <files dir="myLib-2.1"/>
</library>


다음은 설정 태그에 대한 설명이다.

  • <library-name>, <specification-version>, <implementation-version>

    • 애플리케이션이 해당 라이브러리를 참조할 때 사용한다.

    • <*-version> 필드는 같은 이름의 라이브러리가 여러 버전으로 관리되는 경우에 사용될 수 있다.

  • <files>

    실제 라이브러리의 클래스 패스를 설정한다.

    <files> 태그는 다음의 예와 같이 여러 가지 방식으로 클래스 패스를 설정할 수 있다.

    [예 1.2] 공유 라이브러리 <files> 태그

    <files dir=".">
        <include name="a.jar"/>
        <include name="b.jar"/>
    </files>
    
    <files dir="testa"/>
    
    <files dir="/home/works/lib/testc" />
    
    <files dir="/home/works/lib/testd" mode="classes"/>

    • dir 값은 JAR 파일이 담긴 디렉터리 또는 classes 디렉터리가 주어질 수 있으며 상대 경로와 절대 경로 모두 사용할 수 있다. 이때, 상대 경로의 경우 기반(base) 디렉터리로 공유 라이브러리 디렉터리인 JEUS_HOME/lib/shared에 대한 상대 경로로 해석된다.

    • <include> 서브 태그를 이용하여 어떤 JAR 파일들을 포함시킬지 지정할 수 있다. <include> 태그를 전혀 설정하지 않으면 해당 디렉터리의 모든 JAR 파일이 포함된다. 이 경우 해당 디렉터리는 디플로이 시간에 JAR 파일을 동적으로 검색하게 된다. 따라서, 추후에 설정 변경 없이 JAR 파일을 디렉터리에 추가할 수 있다.

      JAR 파일 디렉터리가 아니라 클래스 디렉터리를 지정하고 싶다면, mode 값을 "classes"로 주어야 한다.

    • 새로운 애플리케이션이 디플로이될 때 해당 설정이 수정되었다면 다시 읽어서 처리하기 때문에 라이브러리는 JEUS가 구동 중에도 동적으로 추가될 수 있다. 따라서, JEUS 재기동 없이도 새로운 라이브러리 혹은 업그레이드된 버전의 라이브러리를 추가할 수 있다.

참고

위에 설명한 설정은 해당 XML을 직접 수정해서 할 수도 있지만, WebAdmin을 통해서도 설정할 수 있으니, WebAdmin을 사용할 것을 권장한다.

1.2.3. 애플리케이션에서 라이브러리 참조하기

Java EE 애플리케이션이나 Standalone 모듈은 jeus-application-dd.xml, jeus-web-dd.xml 또는 jeus-ejb-dd.xml의 Entry를 통해 등록된 공유 라이브러리를 사용할 수 있다.

다음은 공유 라이브러리 'myLibrary'를 참조하는 예이다.

<library-ref>
     <library-name>myLibrary</library-name>
</library-ref>

위의 예에서, 애플리케이션은 디플로이될 때 라이브러리 이름이 'myLibrary'인 라이브러리를 찾고 해당 클래스 패스를 애플리케이션 클래스 패스에 추가한다. 여러 버전의 'myLibrary'가 있는 경우 가장 높은(highest) 버전을 선택하게 된다.

참조되는 라이브러리 버전이 설정되지 않으면, 항상 “1.2.5. Version Ordering Rule”에 따라 최상위 버전을 찾게 된다.

다음은 최소 버전이 필요한 경우를 보여주는 예이다.

<library-ref>
     <library-name>myLibrary</library-name>
     <specification-version>2.0</specification-version>
     <implementation-version>2.0</implementation-version>
</library-ref>

다음은 정확한 버전이 필요한 경우의 예이다.

<library-ref>
     <library-name>myLibrary</library-name>
     <specification-version exact-match="true">2.0</specification-version>
     <implementation-version exact-match="true">2.1</implementation-version>
</library-ref>

또는 정해진 스펙 버전만 설정하고 싶다면 다음과 같이 설정한다. 이렇게 되면 해당 스펙 버전의 최상의 implementation version을 찾게 된다.

<library-ref>
     <library-name>myLibrary</library-name>
     <specification-version exact-match="true">2.0</specification-version>
</library-ref>

기본적으로 애플리케이션이 디플로이될 때 참조하고 있는 라이브러리를 찾을 수 없다면 WARNING 로그를 보여주지만, 디플로이는 계속 진행된다. 만약 이런 동작을 원하지 않는다면 다음과 같이 'failonerror' attribute를 설정하여 디플로이를 실패시킬 수 있다.

<library-ref failonerror="true">
     <library-name>myLibrary</library-name>
</library-ref>

1.2.4. 클래스 로딩 방식

공유 라이브러리의 클래스는 어느 곳에서 라이브러리 레퍼런스(reference)를 정의하고 있느냐에 따라서 애플리케이션 클래스 로더 또는 모듈 클래스 로더에 의해서 로딩된다.

예를 들어, 'lib1'이 jeus-application-dd.xml에서 레퍼런스로 정의되었다면 EAR 레벨의 애플리케이션 클래스 로더에 의해서 로딩된다. 하지만 jeus-web-dd.xml에 레퍼런스로 정의되었다면 웹 레벨 클래스 로더에 의해서 로딩된다.

각 애플리케이션 클래스 로더에 의해 로딩된 클래스의 경우 해당 애플리케이션에서만 국한(isolated)되며, 이는 라이브러리도 동일하게 적용된다. 따라서, 클래스 인스턴스는 애플리케이션 간에 공유되지 않는다.

1.2.5. Version Ordering Rule

버전은 "6.2.3-b12"처럼 fraction part(6.2.3)와 non-fraction(string) part(-b12)를 가질 수 있다.

Version ::= <fraction_part> | <string_part> | <fraction_part> <string_part>
fraction_part ::= <integer> | <integer> "." <fraction_part>
string_part ::= <non-numeric> <character>*

버전을 Ordering하는 규칙은 다음과 같다.

  • <fraction part>를 먼저 수치적으로 비교한다. major, minor 순서로 비교된다.

  • <fraction part>가 동일하면 <string part>를 비교한다. 이때 비교는 string 비교 방식을 따른다.

다음은 Ordering 규칙에 따른 순서의 예이다.

6.0 < 6.2.3 < 6.2.3-b12 < 6.2.3-beta < 6.2.4