# **자바 모듈 시스템(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 제공 모듈)** 📌 **`moduleA`는 `MyService` 클래스를 제공**하며, `moduleB`에서 사용 가능하도록 공개해야 한다. #### 📌 **📄 moduleA/src/module-info.java** ```java module com.example.moduleA { exports com.example.moduleA; // 패키지 공개 } ``` #### 📌 **📄 moduleA/src/com/example/moduleA/MyService.java** ```java package com.example.moduleA; public class MyService { public String getMessage() { return "Hello from Module A!"; } } ``` --- ### ✅ **2. `moduleB` (API 사용 모듈)** 📌 **`moduleB`는 `moduleA`의 클래스를 사용**하므로, `requires` 키워드로 `moduleA`를 포함해야 한다. #### 📌 **📄 moduleB/src/module-info.java** ```java module com.example.moduleB { requires com.example.moduleA; // moduleA를 사용하기 위해 선언 } ``` #### 📌 **📄 moduleB/src/com/example/moduleB/MainApp.java** ```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. 모듈별 컴파일** ```sh # 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. 프로그램 실행** ```sh java --module-path out/moduleA:out/moduleB --module com.example.moduleB/com.example.moduleB.MainApp ``` ✔ `Hello from Module A!` 출력 --- ## **5. `exports`와 `opens` 차이점** | 키워드 | 설명 | |--------|------| | `exports 패키지명;` | 패키지를 외부 모듈에서 사용할 수 있도록 공개 | | `opens 패키지명;` | 리플렉션(Reflection)으로 접근 가능하지만 일반적인 import는 불가능 | 📌 예를 들어, **Jackson, Hibernate 같은 프레임워크는 리플렉션을 사용**하므로 `opens`가 필요하다. ```java 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. 결론** 자바 모듈 시스템은 **의존성을 명확하게 관리하고 캡슐화를 강화**하는 강력한 기능이다. 하지만, 기존 라이브러리와의 호환성을 고려해야 하며, **소규모 프로젝트에서는 필요하지 않을 수도 있다.** 대규모 프로젝트에서는 **모듈을 도입하면 유지보수성과 성능이 향상**될 수 있다.