자바 언어·플랫폼 용어 사전
모던 자바모듈 시스템 · module-info · requires · exports · 클래스패스 지옥

JPMS

Java 9의 모듈 시스템. 패키지 단위 공개 범위와 의존을 컴파일 타임에 선언한다.

Java 9의 모듈 시스템(Java Platform Module System). 무엇을 공개하고 무엇에 의존하는지를 선언한다.

// module-info.java
module com.example.order {
    requires com.example.payment;      // 이 모듈에 의존한다
    requires transitive java.sql;      // 나를 쓰는 쪽에도 전파된다
    exports com.example.order.api;     // 이 패키지만 공개한다
    opens   com.example.order.entity;  // 리플렉션만 허용 (JPA·Jackson 용)
}

무엇이 달라지나

public 의 의미가 바뀐다
  기존   public = 클래스패스의 누구나 접근 가능
  모듈   public + exports 된 패키지 = 접근 가능
         exports 안 된 패키지의 public 은 밖에서 못 쓴다
  • "내부 구현" 을 언어 차원에서 숨길 수 있게 됐다
    • 그전에는 impl · internal 같은 패키지명 관례가 전부였다

해결하려던 문제

  • ① 클래스패스 지옥

    • 같은 클래스가 여러 jar 에 있으면 앞선 것이 이긴다 (조용히)
    • 빠진 의존성은 실행 중 NoClassDefFoundError 로 드러난다
    • 모듈은 시작 시점에 그래프를 검증한다
  • ② 강한 캡슐화

    • sun.misc.Unsafe 같은 내부 API 를 아무나 썼다
    • JDK 를 못 바꾸게 만드는 족쇄가 됐다
  • ③ 런타임 축소

    • jlink 로 필요한 모듈만 담은 런타임 이미지를 만든다
    • 컨테이너 이미지가 작아진다

실무에서의 현실

  • 애플리케이션이 module-info 를 쓰는 비율은 낮다

    • (Spring Boot 생태계는 대체로 클래스패스로 동작한다)
  • 그러나 JDK 자체는 모듈화됐다

    • 리플렉션으로 내부 API 를 건드리면 경고·차단이 난다
      • InaccessibleObjectException / --add-opens 요구
  • Java 17 부터 강한 캡슐화가 기본이라 낡은 라이브러리가 여기서 깨진다

  • 마이그레이션에서 만나는 대부분의 문제가 이 지점이다

자동 모듈

module-info 가 없는 jar 를 모듈 경로에 두면 jar 이름으로 자동 모듈이 만들어지고 모든 패키지가 exports 된다

  • 점진적 이행을 위한 장치지만, 이름이 불안정해 배포에는 권장되지 않는다

마이그레이션에서 실제로 부딪히는 것

InaccessibleObjectException: Unable to make field ... accessible

  • 원인 — 라이브러리가 리플렉션으로 JDK 내부에 접근한다
  • 임시 — --add-opens java.base/java.lang=ALL-UNNAMED
  • 근본 — 라이브러리를 최신으로 올린다

Java 16 까지는 경고만, 17 부터는 오류다 그래서 8/11 → 17 이행에서 이 오류가 몰려 나온다

split package 문제

같은 패키지가 두 모듈/jar 에 나뉘어 있으면 모듈 경로에서 거부된다 클래스패스에서는 조용히 동작하던 것이 오류가 된다

  • 대표 사례: javax.annotation 이 여러 jar 에 흩어져 있던 상황
  • Java EE 패키지들이 JDK 에서 분리되며 정리된 배경이기도 하다

필요한 모듈만 담은 런타임 이미지를 만든다

  • JDK 전체 ~300MB → 필요한 것만 ~40MB

컨테이너 이미지 크기와 기동 시간에 직접 영향을 준다 다만 애플리케이션이 모듈화돼 있지 않으면 효과가 제한적이다

면접 함정

  • "Java 9부터 모듈을 써야 한다" → 클래스패스로도 계속 동작한다.
  • "exports와 opens는 같다" → opens는 리플렉션 전용 허용이다.

함께 보면 좋은 용어

노트에서 맥락과 함께 보기 — 모듈·모던 Java