- [Java] Java Platform Module System2026년 03월 17일
- 아몬드맛빼빼로
- 작성자
- 2026.03.17.:32

JPMS
JPMS(Java Platform Module System)는 Java 9부터 도입되어 Java 애플리케이션의 구조화를 개선하기 위해 만들어진 시스템이다. 기존에도 Gradle과 같은 빌드 도구를 이용해 멀티 모듈을 사용할 수 있었지만 JPMS를 사용하여 빌드 도구 없이도 모듈을 분리할 수 있게 되었고 이를 통하여 패키지(Package) 기반 관리의 한계를 뛰어넘을 수 있게 되었다.
패키지의 한계?
패키지를 사용하여 클래스/인터페이스 등을 논리적으로 분할하고 그룹화할 수 있는데 이를 통하여 패키지 단위로 컴파일할 수도 있었고 배포될 수도 있었다. 그러나 Java 애플리케이션의 규모가 커지면서 여러 문제가 가시화되었는데 예를 들어 클래스는 접근 지정자(public, private, protected 등)로 공개 여부와 그 정도를 제어할 수 있지만 패키지는 공개/비공개 2가지 상태만 가능하였고 Java는 동적 로딩을 하여 필요한 클래스를 런타임에 로드할 수 있지만 정작 실행 직후에 그 클래스의 누락 사실을 즉시 알 수 없다는 문제가 있다던가 하였다. 결정적으로 Java 그 자체의 모든 클래스는 단일 파일로 통합되어 배포되는데 이 크기가 Java 9 기준으로 2만 개 클래스를 포함하는 거대 배포 파일이 되었고 Java가 발전할수록 이는 늘어날 것이 분명했기에 필요한 클래스만 가져와 런타임을 생성하고 프로덕션을 배포할 때 불필요한 파일은 포함되지 않도록 하는 방안이 필요하게 되었다.
설정 방법
모듈에 JPMS를 설정하는 방법은 아주 간단한데 module-info.java를 추가해주기만 하면 해당 모듈을 JPMS를 사용하는 것을 인식한다.

module ModuleName { }다음과 같은 본문 형식으로 적으며 module 키워드를 활용해 선언할 수 있다. 이제 중괄호 안에 다양한 키워드를 사용해 모듈간의 종속성을 표현하고 공개 여부를 설정하는 등의 작업을 수행할 수 있다.
주요 키워드
module-info.java의 중괄호 안에서 사용할 수 있는 키워드들은 다음과 같다.
exports
module com.example.mymodule { exports com.example.mypackage; }exports는 해당 모듈의 특정 패키지를 외부에 공개할 때 사용한다. 위 예시처럼 선언하면 com.example.mypackage 패키지의 public 클래스들이 다른 모듈에서 접근 가능해진다. exports 되지 않은 패키지는 모듈 외부에서 접근 자체가 불가능하며, 이것이 기존 패키지 시스템의 공개/비공개 2단계 한계를 극복하는 핵심 기능이다.
특정 모듈에만 선택적으로 공개하고 싶다면 exports ... to 구문을 사용할 수 있다.
module com.example.mymodule { exports com.example.mypackage to com.example.other; }requires
module com.example.mymodule { requires com.example.dependency; }requires는 현재 모듈이 의존하는 다른 모듈을 선언할 때 사용한다. 이를 통해 모듈 간의 의존 관계가 명시적으로 표현되며, 선언된 모듈이 존재하지 않으면 컴파일 시점에 즉시 오류가 발생한다. 앞서 언급한 런타임까지 누락 사실을 알 수 없던 문제가 이 키워드를 통해 해소된다.
추가적으로 requires transitive를 사용하면 의존 모듈을 전이적으로 노출할 수 있다.
module com.example.mymodule { requires transitive com.example.dependency; }requires transitive로 선언하면 com.example.mymodule을 requires 한 모듈도 자동으로 com.example.dependency에 접근할 수 있게 된다. 라이브러리를 제공하는 입장에서 사용자가 일일이 하위 의존성을 선언하지 않아도 되도록 편의를 제공할 때 유용하다.
opens
module com.example.mymodule { opens com.example.mypackage; }opens는 리플렉션(Reflection)을 허용할 때 사용한다. exports는 컴파일 타임과 런타임 모두에서 접근을 허용하지만, opens는 런타임에 한해 리플렉션을 통한 접근을 허용한다. Spring, Hibernate와 같은 프레임워크들이 내부적으로 리플렉션을 사용하기 때문에 이러한 프레임워크와 함께 JPMS를 사용할 때 자주 등장하는 키워드다.
exports... to와 마찬가지로 opens... to로 특정 모듈에만 리플렉션을 허용하는 것도 가능하다.
uses / provides
module com.example.mymodule { uses com.example.MyService; }module com.example.provider { provides com.example.MyService with com.example.MyServiceImpl; }uses와 provides는 Java의 서비스 로더(ServiceLoader) 메커니즘과 연계되는 키워드다. uses는 현재 모듈이 특정 서비스 인터페이스를 사용함을 선언하고, provides... with는 해당 인터페이스의 구현체를 제공함을 선언한다. 이를 통해 인터페이스와 구현체를 서로 다른 모듈로 완전히 분리하는 플러그인 구조를 구현할 수 있다.
모듈 유형
JPMS에서 모듈은 선언 방식과 위치에 따라 몇 가지 유형으로 나뉜다.
Named Module은 module-info.java를 통해 명시적으로 이름이 부여된 모듈이다. 앞서 설명한 모든 키워드가 적용되는 일반적인 형태다.
Unnamed Module은 module-info.java가 없는 JAR 파일이나 클래스패스(classpath)에 올라간 코드들이 해당된다. 하위 호환성을 위해 존재하며, Unnamed Module은 모든 패키지를 자동으로 exports 하고 모든 Named Module에 접근할 수 있다. 다만 Named Module에서는 Unnamed Module을 requires로 선언할 수 없다.
Automatic Module은 module-info.java는 없지만 모듈 경로(modulepath)에 배치된 JAR 파일이다. JAR 파일 이름을 기반으로 자동으로 모듈 이름이 부여되며, 모든 패키지를 exports하고 다른 모든 모듈을 requires 한 것처럼 동작한다. 아직 JPMS를 지원하지 않는 서드파티 라이브러리를 Named Module 환경에서 사용할 때 과도기적으로 활용하는 유형이다.
jlink를 통한 커스텀 런타임 생성
JPMS의 도입 배경에서 언급된 "필요한 클래스만 가져와 런타임을 생성"하는 것을 실제로 가능하게 해주는 도구가 jlink다. 모듈 간 의존 관계가 명확하게 선언되어 있기 때문에, jlink는 애플리케이션이 실제로 필요한 모듈만을 추려 최소화된 JRE 이미지를 생성할 수 있다.
jlink --module-path $JAVA_HOME/jmods:mods \ --add-modules com.example.mymodule \ --output myruntime이렇게 생성된 런타임은 Java가 설치되지 않은 환경에서도 독립적으로 실행 가능하며, 수백 MB에 달하던 전체 JRE 대비 수십 MB 수준으로 크기를 줄일 수 있다. 컨테이너 기반의 프로덕션 배포 환경에서 특히 유용하게 활용된다.
반응형'Java' 카테고리의 다른 글
[Java] GC 알고리즘? (0) 2026.03.16 [Java] Jackson 3.0 (0) 2025.12.08 [Java] Gradle 9.0 (0) 2025.12.03 [Java] WAR vs JAR (0) 2025.12.01 [Java] Java RMI (0) 2025.10.06 다음글이전글이전 글이 없습니다.댓글