BackEnd/Java

Java 9. JPMS

hanseom 2024. 12. 2. 19:00
반응형

자바 플랫폼 모듈 시스템(JPMS)

  JPMS(Java Platform Module System)를 사용하면 코드의 재사용성, 유지보수성, 보안성을 향상시킬 수 있습니다. 모듈은 고유한 이름을 가지며, 관련된 패키지, 리소스, 모듈 디스크립터(module-info.java)로 구성됩니다. JPMS는 빌드 도구 없이도 모듈을 구성할 수 있고, JDK에서 필요한 일부 코드(모듈)만 다운로드할 수 있어 성능과 용량 측면에서 유지보수성을 높일 수 있습니다.

 

JPMS 주요 특징

  • 신뢰적인 구성: 모듈 간 의존성을 명시적으로 선언할 수 있습니다.
  • 강력한 캡슐화: 모듈 내부의 패키지를 다른 모듈로부터 숨길 수 있습니다.
  • 확장성: 여러 모듈로 나누어 필요한 모듈만 사용할 수 있게 합니다.
  • 성능 향상: 필요한 모듈만 로드하므로, 메모리 사용량을 줄이고 시작 시간을 단축시킵니다.

 

  모듈의 등장으로 모든 코드는 Named Module, Unnamed Module 두 가지로 구분됩니다.

Named Module

  • 명시적으로 정의된 모듈로, module-info.java 파일을 통해 선언됩니다.
  • 모듈 경로(module path)에 위치하며, 고유한 이름을 가집니다.
  • 의존성과 노출할 패키지를 명시적으로 선언합니다.

 

Unnamed Module

  • 모듈 시스템 도입 이전의 레거시 코드와의 호환성을 위해 존재합니다.
  • 클래스패스에 있는 모든 클래스와 JAR 파일이 자동으로 unnamed module에 포함됩니다.
  • 이름이 없으며, 모든 패키지를 자동으로 외부에 노출합니다.
  • 모든 다른 모듈을 읽을 수 있지만, named module은 unnamed module을 직접 읽을 수 없습니다.

 

JPMS 예제

  다음은 com.example.hello 모듈에서 HelloWorld 클래스를 외부로 공개하고(exports), com.example.main 모듈이 사용하는 예제입니다.

 

 

패키지 구조

project_root/
├── com.example.hello/
│   ├── src/
│   │   ├── com/
│   │   │   └── example/
│   │   │       └── hello/
│   │   │           └── HelloWorld.java
│   │   └── module-info.java
│   └── com.example.hello.jar
└── com.example.main/
    ├── src/
    │   ├── com/
    │   │   └── example/
    │   │       └── main/
    │   │           └── Main.java
    │   └── module-info.java
    └── com.example.main.jar

 

com.example.hello 모듈

package com.example.hello;

public class HelloWorld {
    public static void sayHello() {
        System.out.println("Hello from com.example.hello module!");
    }
}
module com.example.hello {
    exports com.example.hello;
}

 

com.example.main 모듈

package com.example.main;

import com.example.hello.HelloWorld;

public class Main {
    public static void main(String[] args) {
        HelloWorld.sayHello();
    }
}
module com.example.main {
    requires com.example.hello;
}

 

주요 키워드

  • requires: 컴파일 타임과 런타임 모두에서 의존성이 필요하며, 의존성이 현재 모듈에만 적용됩니다.
  • requires static: 컴파일 타임에만 의존성이 필요하고, 런타임에는 선택적입니다. 주로 특정 기능이 런타임에 항상 필요하지 않은 경우 사용됩니다.
  • requires transitive: 의존성이 현재 모듈과 이를 의존하는 모든 모듈로 전파됩니다.
  • exports: 특정 패키지 전체를 누구에게나 노출합니다.
  • exports ~ to: 특정 패키지를 특정 모듈에만 노출합니다.
  • open: 모듈 전체에 대한 deep reflection을 허가합니다.
  • opens: 특정 패키지에 대한 deep reflection을 허가합니다.
  • opens ~ to: 특정 모듈에만 특정 패키지의 deep reflection을 허가합니다.
  • provides ... with ...: 서비스 구현체들을 등록합니다.
  • uses: 특정 서비스 인터페이스를 사용합니다.

 

JPMS 적용 이후 변경된 점

클래스 로더의 구성 변경

Java 9 이전

  • Bootstrap 클래스 로더: 가장 기본적인 클래스들을 가져옵니다.
  • Extensions 클래스 로더: 추가적인 클래스들을 가져옵니다. 폴더 경로로 구분합니다.
  • System 클래스 로더: classpath에서 찾을 수 있는 클래스들을 가져옵니다.

Java 9 이후

  • Bootstrap 클래스 로더: java.base 모듈의 클래스들을 가져옵니다.
  • Platform 클래스 로더: Bootstrap 클래스 로더가 처리하지 않는 Java SE Platform or JCP 모듈의 클래스들을 가져옵니다.
  • Application 클래스 로더: Java SE Platform 혹은 JDK 안에 있지 않은 클래스들을 가져옵니다.

JRE, JDK의 구성 변경

  • rt.jar, tools.jar 등 JRE / JDK 내부에 있던 몇 가지 파일이 삭제되었습니다.
  • JRE / JDK 디렉토리 구성에도 모듈에 맞게 약간의 변화가 있습니다.
  • Modular Image: 필요한 모듈들만 갖고 있는 JRE / JDK를 구성할 수 있습니다.
반응형