6장. JBoss EAP 모듈 아키텍처
JBoss EAP 5에서는 JBoss Microcontainer를 이용한 아키텍처를 사용하고 있었다. JBoss EAP 5의 각 서비스는 POJO나 JMX MBean로 구현된 모듈로 제공되며 이것들을 Microcontainer가 로드한다. HTTP나 JMS등의 여러 가지 기능을 제공하거나 각 서비스를 유연하게 추가하거나 제거하는 것이 가능했었다.
JBoss EAP 6에서는 이 모듈화를 더욱 개선하여 JBoss Module과 MSC(Modular Service Container)로 불리는 관리 기능으로 한층 더 개선시켜 개별적으로 로드 가능한 모듈 아키텍처를 적용하였다.
각각의 모듈에 대하여 기능을 설정하는 서브시스템은 Java EE의 표준을 제공하는 모듈로 JBoss 시작시의 코어 기능을 제공하는 핵심 서브시스템(Core Subsystems), 클러스터 기능을 제공하는 것 등 여러 가지 기능을 제공하는 모듈이다. 어느 서브시스템을 이용할지는 프로파일로 불리는 서브시스템 세트를 설정 파일(statndalone.xml, domain.xml)로 정의할 수가 있다.
JBoss EAP 6의 시작시 맨 처음에 bootstrap 서비스라는 다른 서비스를 배포하는데 필요 한 최소한의 서비스로 JBoss Module, MSC(Modular Service Container)와 코어 서비스인 Threads, Logging, Deployment Scanner, Remoting을 시작하고, 이후에 그 외의 서비스들을 배포하게 되었다. 쉽게 말하자면 JBoss EAP 6 자체도 서브시스템으로부터 구성되어 있기 때문에 모듈의 집합체가 곧 JBoss EAP 6라고 할 수 있다. 또한 JBoss EAP 6는 이러한 서브시스템을 관리할 수 있는 운용 관리 서비스로서 Management를 제공한다. 관리 CLI나 관리 콘솔이라고 하는 운용 관리도구는 Management에 요청을 보내 결과를 수신한다.
JBoss EAP 6의 아키텍처와 JBoss EAP 6에서 제공하는 서브시스템의 관계는 그림과 같다.

그림 1. JBoss EAP 6 아키텍처
이 장에서는 JBoss EAP 6의 핵심 아키텍처라고 할 수 있는 모듈에 대해서 설명한다. 모듈은 클래스 로딩을 담당하기 때문에 클래스 로딩에 대해서도 설명하고 설정 방법을 소개한다.
1.클래스로더 및 모듈 소개
JBoss EAP 6에서는 배포된 애플리케이션의 클래스 패스를 제어하기 위한 새로운 모듈 형식의 클래스 로드 시스템을 사용한다. 이 시스템은 기존의 계층형 클래스 로더보다 유연하고 관리 기능이 매우 강력해졌다. 개발자가 애플리케이션에서 사용할 수 있는 클래스에 대해 상세한 제어가 가능하여 애플리케이션 서버에서 제공하는 클래스를 무시하고 자신의 클래스를 사용하도록 설 정할 수도 있다.
모듈 형식의 클래스 로더는 모든 Java 클래스를 모듈이라는 논리 그룹으로 나눈다. 각 모듈은 자신의 클래스 패스에 추가된 모듈에서 다른 모듈 의존성을 정의할 수 있다. 모듈 시스템은 JBoss EAP 6에 패키지 된 모든 Java 클래스와 배포된 애플리케이션의 Java 클래스에 적용된다.
JBoss EAP 6에서 배포하는 각각 JAR 및 WAR 파일도 모듈로 취급되기 때문에 개발자는 모듈 설정과 의존성을 추가하여 애플리케이션의 클래스 패스 내용을 쉽게 제어 할 수 있다.
JBoss Modules 와 MSC
JBoss EAP 6에서는 JBoss 모듈 서비스 컨테이너(이하, MSC)가 적용되어 애플리케이션 서버의 서브시스템(EJB, 서블릿, JNDI 바인딩 등)의 각 모듈로부터 사용자 애플리케이션까지 MSC 상에서 동작하는 모듈 서비스로 구성하고 있다.
모듈 서비스가 그냥 서비스로 불리기도 한다. 모듈 서비스는 개별적으로 시작, 정지할 수 있다. 또, 모듈 서비스간에는 의존관계(dependencies)가 있어 어느 모듈 서비스에서 필요한 다른 모듈 서비스로 의존성을 정의할 수 있기 때문에 다른 모듈 서비스를 주입하는 일도 가능하다. MSC에서는 사용하려는 모듈 서비스에 관한 모든 의존성이 채워지면, 그 모듈 서비스를 시작한다. 반대로 의존성 중 1개라도 빠졌을 경우엔 해당의 모듈 서비스는 MSC에 의해 정지된다.

그림 2. JBoss MSC 의 코어 서비스
모듈 서비스에 서 사용되는 용어들을 정리해보면 다음 표와 같다.
| 구분 | 작업 |
|---|---|
| 서비스 컨트롤러 | 서브시스템이나 모듈 등이 서비스로서 실행될 수 있도록 서비스 인터페이스를 제공하거나 서비스에 대한 제어를 담당한다. |
| 서비스 빌더 | 서브시스템이 서비스를 설치하기 위해 필요한 처리를 하는 빌더 기능을 제공한다. |
| 서비스 레지스트리 | 서비스 빌더를 이용해 서비스를 실행할 때 레지스트리에 서비스명과 서비스 컨트롤러를 등록한다. MSC는 이 레지스트리를 참조하여 적합한 서비스 컨트롤러를 반환하여 서비스를 제어하게 된다. |
| 인젝터 | 서비스 빌더가 서비스를 실행할 때 서비스가 의존하는 모듈을 인젝션 하지만 이것도 MSC에서 수행된다. 인젝션 할 때에 필요한 기능이 인젝터(injector)이고, 의존성이 정의되어 있어야 한다. 또, 모든 서비스 인스턴스로 접근은 Value 인터페이스에 의해 정의되고 있다. |
| Concurrent 서비스 컨테이너 | 모든 서비스를 제어하는 기반이 되는 중요한 컴포넌트이다. 이 컨테이너는 서비스를 시작하기 위해 필요한 작업을 태스크화하여 그 태스크를 멀티 스레드로 처리하고 있다. JBoss를 시작하는데 필요한 bootstrap 처리 등도 리스너 태스크로서 등록해 처리한다. |
표 1. 모듈의 주요 용어
2.모듈
모듈은 클래스 로드 및 의존성 관리를 위해 사용되는 클래스의 논리적 그룹이다. 모듈은 필요할 때만 로드 된다. 일반적으로 명시적, 암시적 의존성이 있는 애플리케이션이 배포될 경우에만 실행된다.
JBoss EAP 6에서 모듈을 다음과 같이 정의할 수 있다.
- 클래스를 로드할 때 묶음 단위
- 일반적으로 하나의 jar 파일
- 여러 개의 jar파일이나 프로퍼티 파일 등 자원을 포함할 수 있음
- 모듈 하나에 대해서 하나의 클래스 로더
- 각 모듈은 런타임에 필요한 의존 모듈을 정의
- 계층형 클래스 로더 구조가 아닌 그래프 클래스 로더 구조
- ‘클래스 패스’는 없음
JBoss EAP 6에는 정적 모듈(Static module)과 다이내믹 모듈(Dynamic Module)의 두 가지 모듈이 있다. 이 두 가지 모듈의 차이점은 패키징 방법이 다를 뿐이며, 모든 모듈은 동일한 기능을 갖는다.
| 구분 | 설명 |
|---|---|
| 정적 모듈 (Module 디렉터리에 저장 방식) | 정적 모듈은 애플리케이션 서버 $JBOSS_HOME/modules/ 디렉터리에 저장되어 배포되었다. 각 하위 디렉터리는 하나의 모듈이고 1 개 또는 여러 개의 JAR 파일 및 설정 파일인 modules.xml가 저장되었다. 모듈의 이름은 module.xml 파일에 정의된다. JBoss EAP 6에서 제공하는 모든 API(Java EE API 및 JBoss Logging과 같은 API 포함)는 정적인 모듈로 제공된다. |
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.0" name="com.mysql">
<resources>
<resource-root path="mysql-connector-java-5.1.15.jar"/>
</resources>
<dependencies>
<module name="javax.api"/>
<module name="javax.transaction.api"/>
</dependencies>
</module>
별도의 외부 라이브러리를 사용하기 위하여 사용자가 직접 지정한 정적 모듈도 서버에 배포할 수 있다. 이러한 라이브러리들은 JBoss 관리자가 라이브러리가 포함된 모듈을 만들어 설치할 수 있다. 사용자 지정 정적 모듈에서도 명시적으로 의존성을 선언할 수 있다. | | 다이내믹 모듈 (배포 방식 모듈) | 다이내믹 모듈은 JAR 또는 WAR 배포(또는 EAR의 하위 배포)시 JBoss EAP 6에서 생성되어 로드된다. 다이내믹 모듈의 이름은 배포 된 파일의 이름이다. 배포되는 애플리케이션도 다른 모듈과 마찬가지로 로드되기 때문에 의존성을 설정할 수 있고 다른 모듈을 참조하여 사용할 수 있다. |
표 2. 정적 모듈과 다이내믹 모듈의 차이
모듈 의존성
모듈 의존성은 모듈이 동작하기 위해 다른 모듈의 클래스가 필요한 경우에 이를 참조하기 위한 선언이다. 명시적으로 다른 모듈의 종속성을 지정하지 않으면 의존성은 전혀 없다. 모듈은 얼마든지 다른 모듈의 의존성을 선언할 수 있다. JBoss EAP 6에서 모듈을 로드 할 때 모듈 클래스 로더가 모듈의 의존성을 분석하고 각 의존성 클래스를 클래스 패스에 추가한다. 지정된 의존성 모듈이 없으면 모듈을 로드 할 수 없어 오류가 발생한다.
배포된 애플리케이션(JAR 및 WAR)은 다이내믹 모듈로 로드 된 의존성을 사용하여 JBoss EAP 6에서 제공하는 API에 액세스한다.
의존성은 두 가지 유형으로 명시적, 암시적 의존성이 있다.
명시적 의존성 관계는 개발자가 설정 파일에서 선언할 수 있다. 정적 모듈 의존성을 modules.xml 파일에 선언할 수 있다. 다이내믹 모듈은 배포의 MANIFEST.MF 또는 jboss-deployment-structure.xml 디스크립터에 의존성을 선언할 수 있다.
명시적 의존성은 선택적(optional)으로 지정할 수 있다. 선택적인 의존성이 로드되지 못한다고 해서 모듈을 로드하는데 실패하지는 않는다. 그러나 이후에 의존성을 정의해도 그것이 모듈의 클래스 패스에 추가되지 않는다. 즉 모듈이 로드 될 때 종속성 모듈을 사용할 수 있어야 한다.
암시적 의존성은 특정 조건 또는 메타 데이터를 발견하면 JBossEAP 6에서 자동으로 추가한다. JBoss EAP 6와 함께 제공되는 Java EE 6 API는 배포시 암시적 의존성이 감지되어 추가된 모듈의 대표적인 예이다.
설정을 통하여 원치 않는 암시적 의존성을 제외 할 수도 있다. jboss-deployment-structure.xml 디스크립터 파일에 <exclusions>를 사용하여 정의하면 된다. 또, JBoss EAP 6에서 암시적 의존성을 추가하려면 WEB-INF/lib 디렉터리에 필요한 JAR파일을 넣는 방법을 일반적으로 사용한다.
모듈의 클래스 패스는 자신의 클래스와 직접적인 의존성을 갖는 것만 포함한다.
모듈은 해당 의존성 중 하나의 의존성 클래스에만 접근할 수 있다. 하지만 모듈은 특정 명시적 의존성을 익스포트 할 수 있다.
| 모듈 의존성 예 | 모듈 A는 모듈 B 에 의존하고, 모듈 B는 모듈 C 에 의존한다. 모듈 A는 모듈 B의 클래스에 접근할 수 있고 모듈 B는 모듈 C 의 클래스에 접근할 수 있다 .하지만 모듈 A는 모듈 C의 클래스는 접근할 수 없다. 다음과 같은 방법을 사용하면 모듈 A에서 모듈 C의 클래스에 접근할 수 있다. . 모듈 A 에서 모듈C에 대한 명시적 의존성을 정의한다. . 모듈 B에서 모듈 C에 대한 의존성을 익스포트한다.

3.배포 시 클래스로딩
클래스 로더의 이해
클래스 로더는 그 이름에서 알 수 있듯이 클래스를 로드하는 것이다. 대개의 자바 개발자는 특별히 의식하지 않고 클래스를 사용하고 있지만, 클래스는 사용되기 전에 반드시 클래스 로더를 통해 JVM(Java Virtual Machine)의 메모리 영역에 로드한된다. 올바른 Java EE 패키징을 위해서는 클래스 로더에 대한 지식이 필수적이다.
클래스 로더를 이해하는 데 가장 중요한 개념은 ‘위임 모델’이다. 아래의 그림에서 자바 가상 머신의 클래스 로더 구조를 살펴보자.

그림 3. Java VM의 클래스 로더
클래스 로더는 필요시 부모 클래스 로더에 클래스의 로드를 부탁하는 구조, 즉 맡기는(위임) 것이다. 예를 들어, 시스템 클래스 로더가 클래스를 로드하려고 할 때 시스템 클래스 로더는 자신의 로컬 클래스 패스, 즉 환경변수 CLASSPATH에서 찾기 전에 먼저 부모인 확장 클래스 로더에 클래스의 로드를 요청하게 된다. 마찬가지로 확장 클래스 로더도 먼저 부모 클래스 로더인 부트 스트랩 클래스 로더에 클래스의 로드를 위임하게 된다. 부모 클래스 로더에서 클래스가 발견된 경우에 거기서 클래스를 로딩하여 종료하게 된다. 부모에 클래스가 없을 때 비로소 자신의 로컬 클래스 패스를 찾게 되고 클래스를 로드하게 된다. 위임 모델에서 중요한 것은 자식이 먼저하는 것이 아니라 먼저 부모에게 위임하는 것이다.
배포시 클래스 로딩
클래스 로딩을 위해 JBoss EAP에서 배포는 모두 모듈로 처리된다. 이러한 배포 형식의 모듈을 다이내믹 모듈이라고 한다. 클래스 로딩의 작동 방식은 배포 유형에 따라 다르다.
| 배포 방식 | 설명 |
|---|---|
| WAR 패키지 | WAR 패키지가 하나의 모듈로 간주된다. WEB-INF/lib 디렉터리의 파일들은 WEB-INF/classes 디렉터리에 있는 클래스와 동일하게 처리된다. WAR로 패키지 된 클래스들은 동일한 클래스 로더에 로드된다. |
| EAR 패키지 | EAR 배포는 여러 개의 모듈로 구성된다. 이 모듈은 다음 규칙에 따라 정의된다. * EAR의 lib/ 디렉터리는 부모 모듈이다. * 또 EAR의 각 WAR 배포는 하나의 모듈이다. * 마찬가지로 EAR 내의 EJB JAR 배포도 하나의 모듈이다. EAR의 WAR, JAR 배포와 같은 서브 배포 모듈은 자동으로 부모 모듈에 의존하지만 하위 배포끼리 자동으로 의존성을 갖지는 않는다. 이것은 하위 배포 단절(subdeployment isolation)이라고 한다. 서브 배포 모듈 간의 명시적 종속 관계는 다른 모듈과 같은 방법으로 추가 할 수 있다. |
| 표 3. WAR 패키지와 EAR 패키지의 동작 방식 |