Files
java-examples/docs/모듈.md

5.0 KiB

자바 모듈 시스템(Module System) 완벽 정리

1. 자바 모듈이란?

자바 9에서 도입된 모듈 시스템코드를 논리적으로 분리하고, 불필요한 의존성을 줄이며, 캡슐화를 강화하는 기능이다.
기존의 JAR 파일을 묶는 개념이 아니라, 모듈 자체가 의존성 관리 및 접근 제어 기능을 갖는다.


2. 모듈의 핵심 개념

모듈의 구성 요소

  1. module-info.java 파일 (모듈의 정의 파일)
  2. 패키지 (캡슐화할 클래스 포함)
  3. 다른 모듈에 대한 의존성 선언

모듈의 주요 키워드

키워드 설명
module 모듈을 정의하는 키워드
requires 다른 모듈을 가져올 때 사용
exports 특정 패키지를 외부에서 사용 가능하도록 공개
opens 리플렉션(Reflection)을 허용 (ex: Jackson, Hibernate)
provides ... with 서비스 제공자 패턴 구현 시 사용
uses 특정 서비스 인터페이스 사용 시 명시

3. 모듈 예제

모듈 프로젝트 구성

다음과 같은 두 개의 모듈이 있다고 가정하자.

  • com.example.moduleA (API를 제공하는 모듈)
  • com.example.moduleB (moduleA의 기능을 사용하는 모듈)

📁 프로젝트 구조

/project
 ├── moduleA
 │   ├── src/com/example/moduleA/MyService.java
 │   ├── src/module-info.java
 │
 ├── moduleB
 │   ├── src/com/example/moduleB/MainApp.java
 │   ├── src/module-info.java

1. moduleA (API 제공 모듈)

📌 moduleAMyService 클래스를 제공하며, moduleB에서 사용 가능하도록 공개해야 한다.

📌 📄 moduleA/src/module-info.java

module com.example.moduleA {
    exports com.example.moduleA; // 패키지 공개
}

📌 📄 moduleA/src/com/example/moduleA/MyService.java

package com.example.moduleA;

public class MyService {
    public String getMessage() {
        return "Hello from Module A!";
    }
}

2. moduleB (API 사용 모듈)

📌 moduleBmoduleA의 클래스를 사용하므로, requires 키워드로 moduleA를 포함해야 한다.

📌 📄 moduleB/src/module-info.java

module com.example.moduleB {
    requires com.example.moduleA; // moduleA를 사용하기 위해 선언
}

📌 📄 moduleB/src/com/example/moduleB/MainApp.java

package com.example.moduleB;

import com.example.moduleA.MyService;

public class MainApp {
    public static void main(String[] args) {
        MyService service = new MyService();
        System.out.println(service.getMessage());
    }
}

4. 모듈 프로젝트 실행 방법

📌 터미널에서 모듈을 직접 컴파일하고 실행할 수도 있다.

1. 모듈별 컴파일

# moduleA 컴파일
javac -d out/moduleA src/moduleA/module-info.java src/moduleA/com/example/moduleA/MyService.java

# moduleB 컴파일 (moduleA를 classpath에 추가)
javac -d out/moduleB --module-path out/moduleA src/moduleB/module-info.java src/moduleB/com/example/moduleB/MainApp.java

2. 프로그램 실행

java --module-path out/moduleA:out/moduleB --module com.example.moduleB/com.example.moduleB.MainApp

Hello from Module A! 출력


5. exportsopens 차이점

키워드 설명
exports 패키지명; 패키지를 외부 모듈에서 사용할 수 있도록 공개
opens 패키지명; 리플렉션(Reflection)으로 접근 가능하지만 일반적인 import는 불가능

📌 예를 들어, Jackson, Hibernate 같은 프레임워크는 리플렉션을 사용하므로 opens가 필요하다.

module com.example.moduleA {
    opens com.example.moduleA to jackson.databind;
}

6. 모듈 시스템의 장점

1. 강력한 캡슐화:
필요한 패키지만 exports 가능하여, 불필요한 내부 코드 노출 방지

2. 명확한 의존성 관리:
requires 키워드로 명확한 모듈 간 의존성을 선언

3. 경량화된 런타임:
JVM이 필요 없는 모듈을 제외하고 실행 가능 (예: jlink 사용)


7. 모듈 시스템의 단점

1. 기존 라이브러리와의 호환성 문제:
기존 JAR 파일 중에는 모듈 시스템을 지원하지 않는 것들이 있음

2. 학습 곡선이 존재:
모듈 시스템을 처음 접하는 경우, 기존 classpath 방식보다 설정이 다소 복잡


8. 결론

자바 모듈 시스템은 의존성을 명확하게 관리하고 캡슐화를 강화하는 강력한 기능이다.
하지만, 기존 라이브러리와의 호환성을 고려해야 하며, 소규모 프로젝트에서는 필요하지 않을 수도 있다.
대규모 프로젝트에서는 모듈을 도입하면 유지보수성과 성능이 향상될 수 있다.