rkaehdaos / spring3-edu-test

spring3-edu-test(신입 교육)
0 stars 0 forks source link

[보류]spring-graalvm-native-plugin 빌드로 전환 #7

Open rkaehdaos opened 7 months ago

rkaehdaos commented 7 months ago

spring-graalvm-native-plugin 적용 보류

추후에 고려사항

추후 다음의 개선 여지가 있다고 생각되면 고려한다.

rkaehdaos commented 7 months ago

org.graalvm.buildtools.native 플러그인과 spring-graalvm-native-plugin은 GraalVM을 사용하여 Java 애플리케이션을 네이티브 이미지로 컴파일하는 과정을 단순화하고 자동화하기 위한 Gradle 플러그인입니다. 이 두 플러그인은 비슷한 목적을 가지고 있지만, 세부적인 용도와 특성에서 차이를 보입니다.

org.graalvm.buildtools.native 플러그인

spring-graalvm-native-plugin

org.graalvm.buildtools.native 없이 spring-graalvm-native-plugin만으로 NATIVE BUILD 가능성

spring-graalvm-native-plugin만으로도 Spring Boot 애플리케이션을 네이티브 이미지로 빌드하는 것이 가능합니다. 실제로 spring-graalvm-native-plugin은 Spring Boot 애플리케이션을 네이티브 이미지로 컴파일하기 위해 필요한 모든 설정과 최적화를 포함하고 있으며, 이 과정을 단순화합니다. 따라서 org.graalvm.buildtools.native 플러그인 없이도 충분히 네이티브 이미지 빌드가 가능합니다. 그러나 일반 Java/Kotlin 애플리케이션을 네이티브 이미지로 빌드하려는 경우나, Spring Boot 이외의 프레임워크를 사용하는 경우에는 org.graalvm.buildtools.native 플러그인이 더 적합할 수 있습니다.

결론

spring-graalvm-native-plugin은 Spring Boot 애플리케이션에 특화되어 있으며, org.graalvm.buildtools.native 없이도 Spring Boot 애플리케이션의 네이티브 이미지 빌드를 충분히 지원합니다. 프로젝트의 요구사

항과 사용하는 기술 스택에 따라 적절한 플러그인을 선택하는 것이 중요합니다. Spring Boot 애플리케이션의 경우 spring-graalvm-native-plugin을, 그 외의 경우에는 org.graalvm.buildtools.native 플러그인을 고려할 수 있습니다.

rkaehdaos commented 7 months ago

gradle 플러그인 반영

ref : https://github.com/ayltai/spring-graalvm-native-plugin

    id 'com.github.ayltai.spring-graalvm-native-plugin' version '1.4.10'
rkaehdaos commented 7 months ago

error

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':compileJava'.
> Could not resolve all files for configuration ':compileClasspath'.
   > Could not resolve org.springframework.experimental:spring-native:0.10.0.
     Required by:
         project :
      > Could not resolve org.springframework.experimental:spring-native:0.10.0.
         > Could not get resource 'https://repo.spring.io/release/org/springframework/experimental/spring-native/0.10.0/spring-native-0.10.0.pom'.
            > Could not GET 'https://repo.spring.io/release/org/springframework/experimental/spring-native/0.10.0/spring-native-0.10.0.pom'. Received status code 401 from server:

gpt 답변

스프링 네이티브(Spring Native)를 사용하기 위해서는 해당 의존성을 프로젝트에 추가해야 합니다. 하지만, Spring Boot 2.4.x 이상 버전부터는 Spring Native가 Spring Boot와 더 밀접하게 통합되었고, Spring Native의 구성 방식이 몇 가지 변경되었습니다.

chatGPT는 거짓말장이.

ㅅㅂ gpt에게 괜히 물어봄

spring 저장소를 추가하면 된다 - maven

<dependencies>
    <!-- ... -->
    <dependency>
        <groupId>org.springframework.experimental</groupId>
        <artifactId>spring-native</artifactId>
        <version>0.12.1</version>
    </dependency>
</dependencies>

// Gradle에서 명시적으로 스프링 네이티브 종속성을 추가할 필요 없이 Spring AOT 플러그인이 자동으로 추가합니다.

rkaehdaos commented 7 months ago

JIT vs AOT

자바의 최신 버전에서 AOT(Ahead-of-Time) 컴파일과 JIT(Just-in-Time) 컴파일은 둘 다 성능 향상을 목적으로 하는 다른 컴파일 방법입니다.

AOT 컴파일 방법:

AOT 컴파일은 애플리케이션 코드를 기계어로 변환하여 실행 파일로 만드는 방법입니다. 이렇게 변환된 코드는 실행할 때마다 다시 컴파일할 필요가 없습니다.

JIT 컴파일 방법:

JIT 컴파일은 애플리케이션을 실행할 때 바이트 코드를 기계어로 컴파일하는 방법입니다. 이는 실행 시간에 동적으로 최적화되는 특징을 가지고 있습니다.

선택 시 고려 사항:

결론적으로, AOT 컴파일은 시작 시간 및 메모리 사용량을 최적화하는 데 유용하며, JIT 컴파일은 동적 최적화와 플랫폼 독립성을 제공하는 데 유용합니다. 선택은 애플리케이션의 요구 사항과 운영 환경에 따라 달라집니다.

rkaehdaos commented 7 months ago

스프링의 새로운 AOT

AOT(Ahead-Of-Time) 컴파일은 프로그램을 실행하기 전에 코드를 머신 코드로 컴파일하는 프로세스입니다. 이는 JIT(Just-In-Time) 컴파일의 대안으로, JIT 컴파일은 프로그램이 실행되는 동안 코드를 컴파일합니다. AOT 컴파일은 애플리케이션의 시작 시간을 단축하고 실행 시간 성능을 향상시킬 수 있지만, 컴파일 시간이 길어지고 결과적인 바이너리 크기가 커질 수 있습니다.

AOT의 장단점

장점:

단점:

Spring Boot의 AOT 기능

Spring Boot의 "새로운" AOT 기능에 대한 언급은, Spring Framework 6와 Spring Boot 3에서 소개된 AOT 기술과 관련이 있습니다. 이전 버전의 Spring Boot에서는 AOT 기능이 명시적으로 제공되지 않았습니다. 그러나 Spring Native 프로젝트의 일환으로, Spring Boot 3와 함께 통합된 새로운 AOT 기능이 소개되었습니다.

새로운 AOT 기능:

기존 기능과의 차이점:

Spring Boot의 새로운 AOT 기능은 애플리케이션의 시작 시간과 성능을 개선하기 위한 중요한 발전입니다. 이 기능을 활용하면, Spring Boot 애플리케이션의 배포와 실행이 더욱 효율적이고 빨라질 수 있습니다.

rkaehdaos commented 7 months ago

spring-graalvm-native-plugin 전환은 필요한가?

org.graalvm.buildtools.native 플러그인과 spring-graalvm-native-plugin (혹은 Spring Native)를 사용하여 생성된 네이티브 이미지 사이의 크기, 성능 및 효율성에는 차이가 있을 수 있습니다. 이 차이는 사용하는 플러그인이 Spring Boot 애플리케이션의 특성을 얼마나 잘 최적화하고 이해하느냐에 따라 달라집니다.

스프링 부트 애플리케이션 최적화

성능 및 효율성 비교

플러그인 변경 고려사항

합은 더욱 개선되어 있으며, 네이티브 이미지 생성 과정에서 여러 최적화와 이점을 제공할 수 있습니다.

결론적으로, 네이티브 이미지의 크기와 성능에 있어서 두 플러그인 사이에 차이가 있을 수 있으며, 특히 Spring Boot 애플리케이션에 대해서는 spring-graalvm-native-plugin이 보다 많은 최적화를 제공할 가능성이 높습니다. 프로젝트의 요구사항과 현재 상황을 고려하여 최적의 선택을 하는 것이 중요합니다.

rkaehdaos commented 7 months ago

기본 config

ref : https://github.com/ayltai/spring-graalvm-native-plugin#configuration


nativeImage {
mainClassName = 'com.example.springboot.Application'
// more option: https://github.com/ayltai/spring-graalvm-native-plugin#configuration
reportExceptionStackTraces = true // Exception시 더 상세 정보 제공
removeUnusedAutoConfig     = true // 사용하지 않는 구성의 제거 비활성화
removeYamlSupport          = false // 스프링부트 Yaml 지원 제거->컴파일 속도↑, binary size↓
//    maxHeapSize                = '6G' // GraalVM native build max java heap

}

rkaehdaos commented 7 months ago

Update Spring Boot annotation

@SpringBootApplication(proxyBeanMethods = false)
public class TomcatApplication {
    public static void main(final String[] args) {
        SpringApplication.run(TomcatApplication.class, args);
    }
}

Build GraalVM Native Image

rkaehdaos commented 7 months ago

일반적인 상황시 장단점

proxyBeanMethods

일반적인 상황에서,

proxyBeanMethods=true의 장점

proxyBeanMethods=false의 단점

결론

proxyBeanMethods=true의 기본 설정은 대부분의 Spring 애플리케이션에서 안전하고 일관된 빈 관리를 위해 권장됩니다. 이 설정은 싱글톤 패턴의 보장과 Spring의 전체적인 빈 생명주기 관리에 도움을 줍니다. 반면, proxyBeanMethods=false 설정은 빈 생성과 관련된 오버헤드를 줄이고 성능을 향상시킬 수 있지만, 빈의 싱글톤 보장 및 빈 간 의존성 관리에 주의해야 합니다. 따라서, proxyBeanMethods=false를 사용할 때는 구성 클래스의 @Bean 메서드 호출이 애플리케이션의 나머지 부분에 영향을 주지 않도록 주의해야 하며, 필요한 경우 명시적인 빈 의존성을 사용하여 빈을 주입해야 합니다.

rkaehdaos commented 7 months ago

native build시

@SpringBootApplication 애노테이션의 proxyBeanMethods 속성은 Spring Framework에서 매우 중요한 역할을 합니다. 이 속성은 Spring Boot 애플리케이션의 구성 클래스에서 @Bean 메서드 간의 호출이 컨테이너를 통해 이루어져야 하는지 여부를 제어합니다.

proxyBeanMethods 정의

proxyBeanMethods가 true일 때의 문제

proxyBeanMethods를 false로 설정할 때의 작용

결론

@SpringBootApplication(proxyBeanMethods = false) 설정은 특히 Spring Boot 애플리케이션을 GraalVM 네이티브 이미지로 컴파일할 때 중요합니다. 이 설정은 애플리케이션의 시작 시간을 단축시키고 네이티브 이미지의 크기와 성능을 최적화하는 데 도움을 줍니다. 그러나 이 설정을 사용할 때는 @Bean 메서드 간에 직접 호출이 싱글톤 인스턴스를 반환하지 않음을 인지하고 있어야 합니다. 대부분의 경우, 이러한 직접 호출은 구성 클래스 내에서만 발생하며, 대부분의 애플리

케이션에서는 문제가 되지 않습니다.

rkaehdaos commented 7 months ago

네, proxyBeanMethods=true일 때 @Bean 메서드 호출 시 컨테이너를 통한다는 말에서 언급된 "컨테이너"는 바로 Spring Framework에서 제공하는 스프링 컨테이너(Spring Container)를 말합니다. 스프링 컨테이너는 스프링 애플리케이션의 핵심이며, 스프링 빈(Bean)의 생명주기와 의존성 관리를 담당합니다.

스프링 컨테이너 정의 및 역할

스프링 컨테이너는 스프링 프레임워크의 핵심 부분으로, 애플리케이션 내의 객체(스프링 빈)를 생성하고, 구성하며, 조립하는 역할을 합니다. 이 컨테이너는 애플리케이션의 구성 정보(예: XML 파일, 애노테이션, Java 설정 파일 등)를 기반으로 빈을 관리합니다. 스프링 컨테이너는 다음과 같은 역할을 수행합니다:

  1. 빈 인스턴스화: 컨테이너는 애플리케이션의 구성 정보를 바탕으로 빈 객체를 생성합니다.
  2. 의존성 주입: 컨테이너는 빈 간의 의존성을 해결하고 필요한 경우 다른 빈을 주입하여 객체 간의 결합도를 낮춥니다.
  3. 빈 생명주기 관리: 컨테이너는 빈의 생성부터 소멸까지 전체 생명주기를 관리합니다. 이는 @PostConstruct, @PreDestroy 같은 콜백 메서드를 통해 구현됩니다.
  4. 빈 포스트 프로세싱: 컨테이너는 빈이 생성되고 의존성이 주입된 후 추가적인 처리를 할 수 있도록 빈 포스트 프로세서(Bean Post Processor)를 제공합니다.

@Bean 메서드와 CGLIB 프록시

proxyBeanMethods=true 설정에서, 스프링은 @Configuration 애노테이션이 붙은 클래스 내부의 @Bean 메서드를 호출할 때마다 해당 메서드 호출을 인터셉트하여 컨테이너를 통하게 합니다. 이를 위해 스프링은 CGLIB(Code Generation Library)을 사용하여 구성 클래스의 프록시를 생성합니다. 이 프록시는 실제 @Bean 메서드 호출 대신 프록시의 메서드를 호출하게 만듭니다. 프록시 메서드는 다음과 같은 과정을 거칩니다:

  1. 프록시는 먼저 스프링 컨테이너를 확인하여 요청된 빈이 이미 생성되어 있는지 검사합니다.
  2. 만약 빈이 이미 존재한다면, 컨테이너는 이 빈 인스턴스를 반환합니다. 이는 @Bean 메서드를 통해 생성된 빈이 싱글톤으로 관리됨을 보장합니다.
  3. 만약 빈이 존재하지 않는다면, 프록시는 원본 @Bean 메서드를 호출하여 빈을 생성하고, 이를 컨테이너에 등록한 후 반환합니다.

이 프로세스는 @Bean 메서드 간에 서로를 호출할 때마다 컨테이너를 통해 해당 빈의 싱글톤 인스턴스가 유지되도록 보장합니다. 이는 스프링의 의존성 주입 원칙을 강화하고,

애플리케이션 내의 빈 관리를 일관되게 유지하는 데 도움을 줍니다. 그러나 이 방식은 추가적인 프록시 호출과 관련된 오버헤드를 발생시키므로, 성능에 민감한 상황에서는 proxyBeanMethods=false 설정을 고려할 수 있습니다.

rkaehdaos commented 7 months ago

객체를 spring bean으로 얻을 떄 얻는 주요 장점

객체를 스프링 빈(Spring Bean)으로 관리함으로써 얻을 수 있는 주요 장점은 다음과 같습니다:

1. 의존성 주입(Dependency Injection)

2. 빈 생명주기 관리

3. AOP(Aspect-Oriented Programming) 지원

4. 통합된 예외 처리

5. 간편한 테스트

6. 선언적 리소스 관리

객체를 스프링

빈으로 관리함으로써 얻을 수 있는 이러한 장점들은 애플리케이션의 개발, 배포 및 유지보수 과정을 대폭 단순화하고 효율화합니다.

rkaehdaos commented 7 months ago

proxyBeanMethods=false시 위의 장점에 미치는 영향?

proxyBeanMethods=false로 설정하더라도, 바로 위에서 언급한 스프링 빈의 6가지 장점을 모두 잃게 되는 것은 아닙니다. proxyBeanMethods 설정은 주로 스프링 빈의 생성 방식과 관련된 것이며, 스프링 컨테이너가 제공하는 다양한 기능과 서비스에 대한 접근성에는 직접적인 영향을 미치지 않습니다. 그러나 proxyBeanMethods=false 설정은 스프링 컨텍스트 내에서 @Bean 메서드 호출의 동작 방식에 영향을 미칩니다. 이 설정이 갖는 주요한 영향을 살펴보겠습니다:

1. 의존성 주입(Dependency Injection) : 컨테이너를 우회하나 DI 기능 자체에는 영향 없음

2. 빈 생명주기 관리: 영향 없음

3. AOP(Aspect-Oriented Programming) 지원: 영향 없음

4. 통합된 예외 처리: 영향 없음

5. 간편한 테스트: 영향 없음

6. 선언적 리소스 관리: 영향 없음

proxyBeanMethods=false 설정은 주로 빈 생성과 관련된 오버헤드를 줄이는 데 목적이 있으며, 스프링 애플리케이션의 대부분의 기능과 장점에는 영향을 미치지 않습니다. 다만, 이 설정을 사용할 때는 @Configuration 클래스 내부에서 @Bean 메서드를 직접 호출할 경우 각 호출이 독립적으로 처리됨을 주의해야 합니다.

rkaehdaos commented 7 months ago

상세 주의점

proxyBeanMethods=false 설정을 사용할 때 @Configuration 클래스 내부에서 @Bean 메서드를 직접 호출하는 경우, 각 호출이 컨테이너를 통하지 않고 직접 Java 메서드 호출로 처리되기 때문에 주의가 필요합니다. 이 설정을 사용할 때 주의해야 할 점과 명시적인 빈 의존성을 사용하는 방법에 대해 설명하겠습니다.

주의 사항

  1. 빈 의존성의 명확성: @Configuration 클래스 내에서 @Bean 메서드를 호출하지 않도록 주의합니다. 대신, 빈의 의존성은 주로 생성자 주입을 통해 제공하는 것이 좋습니다. 이렇게 하면 스프링 컨테이너가 자동으로 의존성을 관리하고, 필요한 빈을 주입할 수 있습니다.

  2. 단일 책임 원칙: 각 @Configuration 클래스가 단일 책임 원칙을 따르도록 설계합니다. 너무 많은 빈을 하나의 구성 클래스에 정의하는 것은 피하고, 관련된 빈들을 그룹화하여 여러 구성 클래스로 나누는 것이 좋습니다.

  3. 빈 간의 명시적 연결: @Configuration 클래스 내에서 @Bean 메서드 간에 의존성이 있는 경우, 해당 의존성을 명시적으로 선언하는 것이 중요합니다. 이는 주로 생성자 주입 또는 @Autowired 애노테이션을 사용하여 수행됩니다.

명시적인 빈 의존성 주입 예시

아래 예시는 proxyBeanMethods=false 설정을 사용할 때, 생성자 주입을 통해 빈 의존성을 명시적으로 주입하는 방법을 보여줍니다.

@Configuration(proxyBeanMethods = false)
public class AppConfig {

    // DataSource 빈 정의
    @Bean
    public DataSource dataSource() {
        return new HikariDataSource();
    }

    // JdbcTemplate 빈 정의, DataSource 의존성 주입
    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
}

이 예시에서 jdbcTemplate 빈은 dataSource 빈에 의존합니다. proxyBeanMethods=false 설정이 적용되어 있기 때문에, dataSource() 메서드를 직접 호출하는 대신, jdbcTemplate 빈을 정의할 때 DataSource 타입의 파라미터를 추가하여 생성자 주입을 사용합니다. 스프링 컨테이너는 dataSource 빈을 자동으로 찾아 jdbcTemplate 빈의 생성자에 주입합니다. 이 방법을 사용하면 각 @Bean 메서드 호출이 스프링 컨테이너를 통하지 않아도, 스프링이 의존성을 관리하고 주입할 수 있습니다.

이와 같이 명시적인 빈 의존성을 사용하면, proxyBeanMethods=false 설정을 사용하면서도 스프링 컨테이너의 의존성 주입 기능을 효과적으로 활용할 수 있습니다. 이는 애플리케이션의 모듈성과 테스트 용이성을 향상시키며, 스프링 빈의 관리를 더욱 명확하고 안정적으로 만듭니다.

rkaehdaos commented 7 months ago

spring.threads.virtual.enabled=true

Spring Boot의 spring.threads.virtual.enabled=true 설정