참고:

GraalVM Native Image 시작하기

소개

이 실습에서는 GraalVM Native Image를 사용하여 클라우드 전용 Java 애플리케이션을 구축하는 프로세스를 단계별로 안내합니다. 본 과정은 Java에 대한 지식을 갖춘 개발자를 대상으로 합니다.

GraalVM Native Image 기술은 Java 코드를 사전에 포함된 실행 파일로 컴파일합니다. 응용 프로그램에서 런타임 시 필요한 코드만 실행 파일에 추가됩니다.

Native Image로 생성된 실행 파일에는 다음과 같은 여러 가지 중요한 이점이 있습니다.

오늘날 많은 마이크로서비스 프레임워크에서 Micronaut, Spring, Helidon, Quarkus 등 GraalVM Native Image를 사용한 사전 컴파일을 지원합니다.

또한 Native Image용 Maven 및 Gradle 플러그인이 있으므로 Java 애플리케이션을 실행 파일로 쉽게 빌드, 테스트 및 실행할 수 있습니다.

주: OCI(Oracle Cloud Infrastructure)는 추가 비용 없이 GraalVM Enterprise를 제공합니다.

예상 랩 시간: 45분

랩 목표

이 연습에서는 다음 작업을 수행합니다.

참고: 랩탑 아이콘이 나타나면 명령을 입력하는 것과 같은 작업을 수행해야 합니다. 이를 위해 시선을 집중하십시오.

# This is where we you will need to do something

STEP 1: 원격 호스트에 연결하고 개발 환경을 확인합니다.

개발 환경은 원격 호스트(Oracle Linux 8, 1 CPU 및 32GB 메모리 포함)에 의해 제공됩니다.
원격 호스트가 준비되기 전에 Luna Labs 데스크탑 환경이 표시되므로 최대 2분이 걸릴 수 있습니다.

Luna Desktop 환경에서 설치 스크립트를 실행하여 원격 호스트에 연결합니다. 이 스크립트는 리소스 탭을 통해 사용할 수 있습니다.

  1. 바탕 화면에서 Luna-Lab.html 아이콘을 두 번 누릅니다. 그러면 Oracle Cloud Infrastructure 자격 증명과 실습 관련 정보가 표시됩니다.

  2. 리소스 탭이 표시됩니다. 컴퓨트 인스턴스가 teh 클라우드에서 프로비저닝되는 동안 리소스 제목 옆에 표시된 안개가 회전합니다.

  3. 인스턴스가 프로비전되면 최대 2분 정도 걸릴 수 있으며 이때 리소스 탭에 다음과 같은 메시지가 표시됩니다.

    루나 리소스 탭

  4. 리소스 탭에서 VS 코드 환경을 설정하는 구성 스크립트를 복사합니다. 세부정보 보기 링크를 눌러 구성을 표시합니다. 아래 스크린샷에 표시된 대로 복사합니다.

    구성 스크립트 복사

  5. 아래 스크린샷에 표시된 대로 터미널을 엽니다.

    터미널 열기@ action: inmenu

  6. 구성 코드를 터미널에 붙여넣어 VS 코드를 엽니다.

    터미널 1 붙여넣기

    터미널 2 붙여넣기

모든 것입니다. 축하합니다. 이제 Oracle Cloud의 원격 호스트에 성공적으로 접속되었습니다!

개발 환경에 대한 참고 사항

이 실습을 위한 Java 플랫폼으로 GraalVM Enterprise 21을 사용합니다. GraalVM은 신뢰할 수 있는 보안 Oracle Java SE에 구축된 Oracle의 고성능 JDK 배포입니다.

개발 환경은 이 실습에 필요한 GraalVM 및 Native Image 툴로 사전 구성되어 있습니다.

터미널에서 이러한 명령을 실행하여 쉽게 확인할 수 있습니다. VS 코드 Terminal > New Terminal 내에서 터미널을 만들 수 있습니다.

java -version

native-image --version

STEP 2: 데모 응용 프로그램 빌드 및 실행

데모 응용 프로그램을 사용하여 GraalVM Native Image: 현재 디렉토리와 해당 하위 디렉토리의 파일 수를 계산하는 명령행 Java 응용 프로그램을 보여줍니다. 또한 응용 프로그램은 총 파일 크기도 계산합니다.

응용 프로그램의 소스 코드는 원격 호스트에서 사용할 수 있습니다.

데모 애플리케이션에 대한 참고 사항

응용 프로그램은 src 디렉토리에서 찾을 수 있는 두 개의 Java 파일로 구성됩니다.

수동으로 또는 Maven 프로파일을 사용하여 응용 프로그램을 빌드할 수 있습니다. Maven 빌드 구성은 pom.xml 파일에서 제공됩니다. Maven 프로파일은 단일 pom.xml 파일 내에서 다른 빌드 구성을 사용하는 좋은 방법입니다. Maven 프로파일에 대한 자세한 내용은 여기서 찾아볼 수 있습니다.

열린 VS 코드 내에서 파일을 찾아볼 수 있습니다.

이 실습에서는 각각 특정 목적을 가진 여러 프로파일이 사용됩니다.

  1. native : 이 프로파일은 GraalVM Native Image를 사용하여 실행 파일을 작성합니다.
  2. java_agent : 이 프로파일은 응용 프로그램에서 모든 동적 코드 사용을 추적하고 이 정보를 구성 파일로 캡처하는 추적 에이전트를 사용하여 Java 응용 프로그램을 작성합니다. 나중에 자세히 알아보겠습니다.

특정 Maven 프로파일을 mvn 명령에 매개변수로 전달하여 사용합니다. 프로파일 이름은 -P 플래그에 추가됩니다. VS 코드 내에서 터미널 내에서 다음 명령을 실행할 수 있습니다.

아래 예제는 Maven을 사용하여 구축할 때 native 프로파일을 호출할 수 있는 방법을 보여줍니다.

mvn clean package -Pnative

이제 응용 프로그램이 실행되는 작업을 기본적으로 이해하여 작동 방식을 확인할 수 있습니다.

  1. VS Code에서 연 터미널 내에서 프로젝트를 빌드하고 실행합니다.

    mvn clean package exec:exec
    

    위 명령은 다음을 수행합니다.

    1. 프로젝트를 정리하여 생성되거나 컴파일된 아티팩트를 제거합니다.
    2. 응용 프로그램을 포함하는 실행 가능한 JAR 파일을 생성합니다. 이 JAR 파일은 나중에 Native Image에서 사용됩니다.
    3. exec 플러그인을 실행하여 응용 프로그램을 실행합니다.

    생성된 출력에 다음이 포함됩니다(응용 프로그램에서 보고된 파일 수는 다를 수 있음).

    Counting directory: .
    Total: 15 files, total size = 511.9 KiB
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
    

STEP 3: Java 응용 프로그램을 실행 파일로 설정합니다.

이제 GraalVM Native Image를 사용하여 응용 프로그램의 실행 버전을 작성합니다. 빠른 미리 알려 드리면 GraalVM Native Image는 Java 애플리케이션을 JDK를 실행할 필요가 없는 자체 포함된 실행 파일로 변환하는 사전 컴파일 기술로서, 빠르고 효율적입니다.

GraalVM Native Image는 원격 호스트에 사전 설치되어 있습니다.

  1. 시작하려면 target 디렉토리에 컴파일된 JAR 파일이 있는지 확인합니다.

    ls ./target
    drwxrwxr-x 1 krf krf    4096 Mar  4 11:12 archive-tmp
    drwxrwxr-x 1 krf krf    4096 Mar  4 11:12 classes
    drwxrwxr-x 1 krf krf    4096 Mar  4 11:12 generated-sources
    -rw-rw-r-- 1 krf krf  496273 Mar  4 11:38 graalvmnidemos-1.0-SNAPSHOT-jar-with-dependencies.jar
    -rw-rw-r-- 1 krf krf    7894 Mar  4 11:38 graalvmnidemos-1.0-SNAPSHOT.jar
    drwxrwxr-x 1 krf krf    4096 Mar  4 11:12 maven-archiver
    drwxrwxr-x 1 krf krf    4096 Mar  4 11:12 maven-status
    

    필요한 파일은 graalvmnidemos-1.0-SNAPSHOT-jar-with-dependencies.jar입니다.

  2. 명령행에서 실행 파일을 생성합니다. GraalVM Native Image를 사용하기 위해 Maven 플러그인을 사용할 필요는 없지만 도움을 줄 수 있습니다. 프로젝트의 루트 디렉토리 demo에서 다음을 실행합니다.

    native-image -jar ./target/graalvmnidemos-1.0-SNAPSHOT-jar-with-dependencies.jar --no-fallback -H:Class=oracle.App -H:Name=file-count
    

    그러면 현재 디렉토리 내에 file-count라는 실행 파일이 생성됩니다.

  3. 다음과 같이 이 실행 파일을 실행합니다.

    ./file-count
    
  4. 이제 응용 프로그램을 시작합니다. 먼저 실행 파일로 실행한 다음 일반 java 명령을 사용하여 실행합니다.

    time ./file-count
    

    time java -cp ./target/graalvmnidemos-1.0-SNAPSHOT-jar-with-dependencies.jar oracle.App
    

    native-image 명령으로 생성된 실행 파일은 해당하는 Java 응용 프로그램보다 훨씬 빠르게 실행됩니다.

실행 파일 작성 방법에 대해 좀 더 자세히 살펴보겠습니다.

2단계에서 native-image 명령으로 전달한 매개변수는 어떻게 지정합니까?

전체 설명서는 여기에서 확인할 수 있습니다.

GraalVM Native Image Maven 플러그인을 사용하여 native-image 툴을 실행할 수도 있습니다. 프로젝트 pom.xml(Maven 구성) 파일에는 플러그인을 사용하여 실행 파일을 작성하는 방법을 보여주는 다음 코드 조각이 포함되어 있습니다.

<!-- Native Image -->
<plugin>
    <groupId>org.graalvm.buildtools</groupId>
    <artifactId>native-maven-plugin</artifactId>
    <version>${native.maven.plugin.version}</version>
    <extensions>true</extensions>
    <executions>
    <execution>
        <id>build-native</id>
        <goals>
        <goal>build</goal>
        </goals>
        <phase>package</phase>
    </execution>
    </executions>
    <configuration>
        <skip>false</skip>
        <imageName>${exe.file.name}</imageName>
        <mainClass>${app.main.class}</mainClass>
        <buildArgs>
            <buildArg>--no-fallback</buildArg>
            <buildArg>--report-unsupported-elements-at-runtime</buildArg>
        </buildArgs>
    </configuration>
</plugin>

Native Image Maven 플러그인은 실행 파일을 많이 생성하는 작업을 수행합니다. <skip>true</skip> 태그를 사용하여 사용 안함으로 설정할 수 있습니다. <buildArgs/> 태그를 통해 native-image에 매개변수를 전달할 수도 있습니다.

GraalVM Native Image 플러그인에 대한 전체 설명서는 여기에서 찾을 수 있습니다.

Maven 프로파일을 사용하여 실행 파일을 작성하려면 다음을 실행합니다.

mvn clean package -Pnative

Maven 빌드는 실행 파일 file-counttarget 디렉토리에 배치합니다.

다음과 같이 실행 파일을 실행할 수 있습니다.

./target/file-count

STEP 4: 반사 사용 - Log4J에 종속성 추가

이 단계에서는 Java의 동적 기능과 함께 작동하는 실행 파일을 작성합니다.

리플렉션에 의존하는 응용 프로그램에 라이브러리 또는 일부 코드를 추가하려고 한다고 가정합니다. 리플렉션 테스트에 적합한 후보는 Log4J 로깅 프레임워크입니다. 프로젝트 pom.xml 파일에 이미 종속성으로 추가되었습니다.

<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

log4j를 사용하도록 응용 프로그램을 변경하려면 ListDir.java 파일을 편집하고 몇 줄의 주석 처리를 해제합니다.

  1. VS 코드를 사용하여 ListDir.java 파일을 엽니다.

  2. log4j 임포트를 선언하는 행의 주석 처리를 해제한 다음 다음 다음 행의 주석 처리를 해제합니다.

    //import org.apache.log4j.Logger;
    

    //final static Logger logger = Logger.getLogger(ListDir.class);
    

    /*
    // Add some logging
    if(logger.isDebugEnabled()){
        logger.debug("Processing : " + dirName);
    }
    */
    

    /*
    // Add some logging
    if(logger.isDebugEnabled()){
        logger.debug("Processing : " + f.getAbsolutePath());
    }
    */
    
  3. 파일을 저장합니다

    이제 응용 프로그램에 로깅을 추가했으므로 재구축 및 실행하여 변경 결과를 볼 수 있습니다.

    mvn clean package exec:exec
    

    앞에서 살펴본 것과 같은 종류의 출력이 나타나지만 로깅을 더 추가하면 됩니다.

  4. 그런 다음 Maven 프로파일을 사용하여 실행 파일을 작성합니다.

    mvn clean package -Pnative
    
  5. 로깅이 포함된 실행 파일을 실행합니다.

    ./target/file-count
    

    오류가 발생합니다.

    Exception in thread "main" java.lang.NoClassDefFoundError
            at org.apache.log4j.Category.class$(Category.java:118)
            at org.apache.log4j.Category.<clinit>(Category.java:118)
            at java.lang.Class.ensureInitialized(DynamicHub.java:552)
            at oracle.ListDir.<clinit>(ListDir.java:75)
            at oracle.App.main(App.java:63)
    Caused by: java.lang.ClassNotFoundException: org.apache.log4j.Category
            at java.lang.Class.forName(DynamicHub.java:1433)
            at java.lang.Class.forName(DynamicHub.java:1408)
            ... 5 more
    

    여기서 무슨 일이 일어난 거지?

Java의 동적 기능 사용

이 예외는 반사에 의존하므로 Log4J 라이브러리를 추가함으로써 발생합니다.
native-image 도구는 공격적인 정적 분석을 수행하여 응용 프로그램 내에서 사용되는 클래스를 확인합니다. 사용되지 않는 클래스에 대해서는 해당 클래스가 필요하지 않다고 가정합니다. 이를 "열린 세계" 가정이라고 합니다. 로드해야 하는 모든 사항은 실행 파일을 작성할 때 알려져야 합니다. 정적 분석으로 찾을 수 없는 경우 실행 파일에 포함되지 않습니다.

Reflection은 Java의 핵심 기능이므로 리플렉션을 사용하고 GraalVM Native Image에서 제공하는 빠른 속도를 활용하는 방법은 무엇입니까? native-image 도구에서 반사 사용에 대해 알아볼 수 있는 방법이 필요합니다.

다행히 native-image 도구는 고찰을 통해 참조되는 모든 클래스를 지정하는 구성 파일에서 읽을 수 있습니다.

이 작업은 수동으로 수행하거나 GraalVM Java 런타임과 함께 제공되는 Java 추적 에이전트를 통해 수행할 수 있습니다. 에이전트는 응용 프로그램이 실행되는 동안 찾을 수 있는 반사, JNI, 프록시 및 리소스 액세스의 모든 인스턴스를 기록하는 JSON 파일을 생성합니다.

: 모든 고찰 사례가 식별되도록 추적 에이전트를 실행할 때 응용 프로그램의 모든 코드 경로를 수행하는 것이 중요합니다.

추적 에이전트에 대한 전체 설명서는 여기에서 확인할 수 있습니다.

STEP 5: 추적 에이전트 사용

이제 응용 프로그램을 실행하는 동안 추적 에이전트를 사용하여 반사 구성을 생성합니다.

  1. 추적 에이전트를 사용하여 응용 프로그램을 실행합니다.

    java -agentlib:native-image-agent=config-output-dir=./src/main/resources/META-INF/native-image -cp ./target/graalvmnidemos-1.0-SNAPSHOT-jar-with-dependencies.jar oracle.App
    

    추적 에이전트가 생성한 구성 파일을 확인합니다.

    ls -l src/main/resources/META-INF/native-image/
    

    생성된 출력에 다음이 포함됩니다.

    total 56
    -rw-r--r--  1 kfoster  staff     4B Dec  2 19:13 jni-config.json
    -rw-r--r--  1 kfoster  staff    86B Nov  9 20:46 native-image.properties
    -rw-r--r--  1 kfoster  staff    65B Dec  2 19:13 predefined-classes-config.json
    -rw-r--r--  1 kfoster  staff     4B Dec  2 19:13 proxy-config.json
    -rw-r--r--  1 kfoster  staff   521B Dec  2 19:13 reflect-config.json
    -rw-r--r--  1 kfoster  staff   101B Dec  2 19:13 resource-config.json
    -rw-r--r--  1 kfoster  staff     4B Dec  2 19:13 serialization-config.json
    

    : 프로젝트에 이 작업을 수행할 수 있는 Maven 프로파일이 포함되어 있습니다. 다음 명령을 실행하여 추적 에이전트를 사용합니다.

    mvn clean package exec:exec -Pjava_agent
    
  2. 이제 실행 파일을 다시 빌드합니다. 이번에는 추적 에이전트로 생성된 구성 파일이 적용됩니다.

    mvn package -Pnative
    
  3. 마지막으로 생성된 파일을 실행합니다.

    time ./target/file-count
    

    실행 파일이 작동하고 예상대로 출력에 로그 메시지를 생성합니다.

이는 추적 에이전트가 생성한 파일이 반사에서 참조하는 클래스를 기록했기 때문입니다. 이제 native-image 도구는 응용 프로그램 내에서 사용되고 있으므로 생성된 실행 파일에서 제외하지 않습니다.

-agentlib 매개변수의 위치에 대한 참고

에이전트 매개변수는 반드시 -jar 또는 -classpath 매개변수 앞에 와야 합니다. 또한 파일을 쓸 디렉토리도 지정해야 합니다. 권장 위치는 src/main/resources/META-INF/native-image 아래에 있습니다. 이 위치에 배치된 파일은 native-image 도구에서 자동으로 선택됩니다.

실행 파일 생성 구성에 대한 참고 사항

Java 속성 파일(기본적으로 src/main/resources/META-INF/native-image/native-image.properties)을 사용하여 native-image 도구로 매개변수를 전달할 수도 있습니다. demo 디렉토리에 가능한 작업을 알려주는 예제 파일이 있습니다.

결론

이 실습에서는 여러 가지 GraalVM Native Image 기능을 사용해 보았습니다.

  1. Java 명령행 응용 프로그램에서 빠른 실행 파일을 생성하는 방법
  2. Maven을 사용하여 실행 파일을 작성하는 방법
  3. 추적 에이전트를 사용하여 반사 추적 및 기록 프로세스를 자동화하는 방법

GraalVM Native Image를 사용하여 효율적이고 안전하며 즉시 확장 가능한 클라우드 네이티브 Java 애플리케이션 작성

더 알아보기

추가 학습 자원

docs.oracle.com/learn에서 다른 실습을 찾아보거나 Oracle Learning YouTube channel에서 무료 학습 콘텐츠에 액세스할 수 있습니다. 또한 education.oracle.com/learning-explorer를 방문하여 Oracle Learning Explorer로 변경하십시오.

제품 설명서는 Oracle Help Center를 참조하십시오.