GraalVM ๋ค์ดํฐ๋ธ ์ด๋ฏธ์ง๋ ์ปดํ์ผ๋ ์๋ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฏธ์น ์ฒ๋ฆฌํ์ฌ ์์ฑํ ์ ์๋ ๋ ๋ฆฝ ์คํํ ์คํ ํ์ผ์ด๋ค. ๋์ปค ์ด๋ฏธ์ง์ ๊ฐ์ ์ด๋ฏธ์ง๋ฅผ ์๋ฏธํ๋ ๊ฒ์ด ์๋๋ค. ๋ค์ดํฐ๋ธ ์ด๋ฏธ์ง๋ ์ผ๋ฐ์ ์ผ๋ก ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ ๊ณต๊ฐ์ด ๋ ์๊ณ JVM ์ด๋ฏธ์ง ๋ณด๋ค ๋น ๋ฅด๊ฒ ์์ํ ์ ์๋ค๋ ์ฅ์ ์ด ์๋ค. ์ปจํ ์ด๋ ์ด๋ฏธ์ง๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐฐํฌํ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ํฉํ๋ฉฐ, ํนํ ์๋น์คํ ๊ธฐ๋ฅ(FaaS) ํ๋ซํผ๊ณผ ๊ฒฐํฉํ ๋ ์ ์ฉํ๋ค. Spring Boot GraalVM ๋ค์ดํฐ๋ธ ์ด๋ฏธ์ง๋ ์์ ํ ํ๋ซํผ๋ณ ์คํํ์ผ์ด๋ค. ์ด๋ฒ ํฌ์คํ ์์๋ Spring Boot ์ GraalVM ๋ค์ดํฐ๋ธ ์ด๋ฏธ์ง ๋น๋๋ฅผ ์ํด์ ์ง์๋๋ ์ฌํญ์ ๋ํ ๊ณต์ ๋ฌธ์๋ฅผ ์ ๋ฆฌํ๊ณ ์ ํ๋ค.
JVM ๋ฐฐํฌ์ ์ฐจ์ด์
- ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ์ ๋ถ์์ ๋ฉ์ธ ์ํธ๋ฆฌ ํฌ์ธํธ์์ ๋น๋ ์ ์ํ๋๋ค.
- ๋ค์ดํฐ๋ธ ์ด๋ฏธ์ง๊ฐ ์์ฑ๋ ๋ ๋๋ฌํ ์ ์๋ ์ฝ๋๋ ์ ๊ฑฐ๋๋ฉฐ ์คํ ํ์ผ์ ์ผ๋ถ๊ฐ ๋์ง ์๋๋ค.
- GraalVM ์ ์ฝ๋์ ๋์ ์์๋ฅผ ์ง์ ์ธ์ํ์ง ๋ชปํ๋ฏ๋ก ๋ฆฌํ๋ ์ , ๋ฆฌ์์ค, ์ง๋ ฌํ ๋ฐ ๋์ ํ๋ก์์ ๋ํด ๋ฏธ๋ฆฌ ์๋ ค์ค์ผ ํ๋ค.
- ์ ํ๋ฆฌ์ผ์ด์ ํด๋์ค ๊ฒฝ๋ก๋ ๋น๋ ์์ ์ ๊ณ ์ ๋๋ฉฐ ๋ณ๊ฒฝํ ์ ์๋ค.
- ์ง์ฐ ํด๋์ค ๋ก๋ฉ์ด ์์ผ๋ฉฐ, ์คํ ํ์ผ์ ํฌํจ๋ ๋ชจ๋ ๊ฒ์ด ์์์ ๋ฉ๋ชจ๋ฆฌ์ ๋ก๋๋๋ค.
- ์๋ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ผ๋ถ ์ธก๋ฉด์ ๋ํด ์์ ํ ์ง์๋์ง ์๋ ๋ช๊ฐ์ง ์ ์ฝ ์ฌํญ์ด ์๋ค.
Spring ์ฌ์ ์ฒ๋ฆฌ
์ผ๋ฐ์ ์ธ Spring Boot ์ ํ๋ฆฌ์ผ์ด์
์ ๋งค์ฐ ๋์ ์ด๋ฉฐ ๊ตฌ์ฑ์ ๋ฐํ์์ ์ํ๋๋ค. ์ค์ ๋ก Spring Boot Auto Configuration ์ ๊ฐ๋
์ ๋ฐํ์์ ์ํ์ ๋ฐ์ํ์ฌ ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌ์ฑํ๋๋ฐ ํฌ๊ฒ ์์กดํ๋ค. ์ ํ๋ฆฌ์ผ์ด์
์ ๋์ ์ธก๋ฉด์ ๋ํด์ GraalVM ์ ์๋ ค์ค ์๋ ์์ง๋ง, ๊ทธ๋ ๊ฒ ํ๋ฉด ์ ์ ๋ถ์์ ์ด์ ์ ๋๋ถ๋ถ ์์คํ๊ฒ ๋๋ฏ๋ก Spring Boot๋ฅผ ์ฌ์ฉํ์ฌ ๋ค์ดํฐ๋ธ ์ด๋ฏธ์ง๋ฅผ ์์ฑํ
๋๋ closed-world ๋ก ๊ฐ์ ๋๊ณ ์ ํ๋ฆฌ์ผ์ด์
์ ๋์ ์ธก๋ฉด์ด ์ ํ๋๋ค.
- ํด๋์ค ๊ฒฝ๋ก๋ ๋น๋ ์์ ์ ๊ณ ์ ๋๊ณ ์์ ํ ์ ์๋๋ค.
- ์ ํ๋ฆฌ์ผ์ด์
์ ์ ์๋ ๋น์ ๋ฐํ์์ ๋ณ๊ฒฝํ ์ ์๋ค.
- Spring @Prifile ์ด๋ ธํ ์ด์ ๋ฐ ํ๋กํ๋ณ ๊ตฌ์ฑ์๋ ์ ํ์ด ์๋ค.
- ๋น์ด ์์ฑ๋๋ฉด ๋ณ๊ฒฝ๋๋ ์์ฑ(@ConditionalOnProperty ๋ฐ .enable ์์ฑ ๋ฑ)์ ์ง์๋์ง ์๋๋ค.
์ด๋ฌํ ์ ์ฝ์ฌํญ์ด ์ ์ฉ๋๋ฉด Spring ์ด ๋น๋ ์๊ฐ ๋์ ์ฌ์ ์ฒ๋ฆฌ๋ฅผ ์ํํ๊ณ GraalVM์ด ์ฌ์ฉํ ์ ์๋ ์ถ๊ฐ ์์ฐ์ ์์ฑํ ์ ์๋ค.
Spring AOT(Ahead-of-Time) ์ฒ๋ฆฌ๋ ์ ํ๋ฆฌ์ผ์ด์
์ ์ผ๋ฐ์ ์ผ๋ก ๋ค์๊ณผ ๊ฐ์ด ์์ฑ๋๋ค.
- Java source code
- Bytecode (for dynmic proxies etc)
- GraalVM JSON hint files
- Resource hints (resource-config.json)
- Reflection hints (reflect-config.json)
- Serialization hints (serialization-config.json)
- Java Proxy hints (proxy-config.json)
- JNI hints (jni-config.json)
Source Code Generation
์๋๋ ์ผ๋ฐ์ ์ธ @Configuration ํด๋์ค ์ฝ๋๋ค.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
public class MyConfiguration {
@Bean
public MyBean myBean() {
return new MyBean();
}
}JavaSpring ์ MyBean ์ธ์คํด์ค๊ฐ ํ์ํ ๊ฒฝ์ฐ myBean() ๋ฉ์๋๋ฅผ ํธ์ถํ๊ณ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค๋ ๊ฒ์ ์๊ณ ์๋ค. JVM ์์ ์คํ๋๋ ๊ฒฝ์ฐ ์ ํ๋ฆฌ์ผ์ด์
์ด ์์๋ ๋ @Configuration ํด๋์ค ๊ตฌ๋ฌธ ๋ถ์์ด ์ํ๋๊ณ ๋ฆฌํ๋ ์
์ ์ฌ์ฉํ์ฌ @Bean ๋ฉ์๋๊ฐ ํธ์ถ๋๋ค.
๋ค์ดํฐ๋ธ ์ด๋ฏธ์ง๋ฅผ ์์ฑํ ๋ Spring ์ ๋ค๋ฅธ ๋ฐฉ์์ผ๋ก ์๋ํ๋ค. ๋ฐํ์์ @Configuration ํด๋์ค๋ฅผ ํ์ฑํ๊ณ ๋น ์ ์๋ฅผ ์์ฑํ๋ ๋์ ๋น๋ ํ์์ ์ด๋ฅผ ์ํํ๋ค. @Bean ์ ์๊ฐ ๋ฐ๊ฒฌ๋๋ฉด ์ด๋ฅผ ์ฒ๋ฆฌํ์ฌ GraalVM ์ปดํ์ผ๋ฌ์์ ๋ถ์ํ ์ ์๋ ์์ค ์ฝ๋๋ก ๋ณํํ๋ค.
Spring AOT ํ๋ก์ธ์ค๋ ์์ Configuration ํด๋์ค๋ฅผ ๋ค์๊ณผ ๊ฐ์ ์ฝ๋๋ก ๋ณํํ๋ค.
import org.springframework.beans.factory.aot.BeanInstanceSupplier;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
/**
* Bean definitions for {@link MyConfiguration}.
*/
public class MyConfiguration__BeanDefinitions {
/**
* Get the bean definition for 'myConfiguration'.
*/
public static BeanDefinition getMyConfigurationBeanDefinition() {
Class<?> beanType = MyConfiguration.class;
RootBeanDefinition beanDefinition = new RootBeanDefinition(beanType);
beanDefinition.setInstanceSupplier(MyConfiguration::new);
return beanDefinition;
}
/**
* Get the bean instance supplier for 'myBean'.
*/
private static BeanInstanceSupplier<MyBean> getMyBeanInstanceSupplier() {
return BeanInstanceSupplier.<MyBean>forFactoryMethod(MyConfiguration.class, "myBean")
.withGenerator((registeredBean) -> registeredBean.getBeanFactory().getBean(MyConfiguration.class).myBean());
}
/**
* Get the bean definition for 'myBean'.
*/
public static BeanDefinition getMyBeanBeanDefinition() {
Class<?> beanType = MyBean.class;
RootBeanDefinition beanDefinition = new RootBeanDefinition(beanType);
beanDefinition.setInstanceSupplier(getMyBeanInstanceSupplier());
return beanDefinition;
}
}JavaSpring AOT ๋ ๋ชจ๋ ๋น ์ ์์ ๋ํด์ ์ด์ ๊ฐ์ ์ฝ๋๋ฅผ ์์ฑํ๋ค. ๋น ์ฌํ ์ฒ๋ฆฌ๊ฐ ํ์ํ ๊ฒฝ์ฐ(@Autowired ๋ฉ์๋ ํธ์ถ ๊ฐ์) ์ฝ๋๋ฅผ ์์ฑํ๋ค. ๋ํ AOT ์ฒ๋ฆฌ๋ ์ ํ๋ฆฌ์ผ์ด์
์ด ์ค์ ๋ก ์คํ๋ ๋ Spring Boot ์์ ApplicationContext๋ฅผ ์ด๊ธฐํ ํ๋๋ฐ ์ฌ์ฉ๋๋ ApplicationContextInitializer๊ฐ ์์ฑ๋๋ค.
AOT๋ก ์์ฑ๋ ์ฝ๋๋ Maven ์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ์๋ target/spring-aot/main/sources ์์, gradle ์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ build/generated/aotSources ์์ ์ฐพ์ ์ ์๋ค.

Spring Boot GraalVM Hint File Generation
์์ค ํ์ผ์ ์์ฑํ๋ ๊ฒ ์ธ์๋ Spring AOT ์์ง์ GraalVM ์์ ์ฌ์ฉํ๋ ํํธ ํ์ผ๋ ์์ฑํ๋ค. ํํธ ํ์ผ์๋ ์ฝ๋๋ฅผ ์ง์ ๊ฒ์ฌํ์ฌ ์ดํดํ ์ ์๋ ์ฌํญ์ GraalVM์ด ์ด๋ป๊ฒ ์ฒ๋ฆฌํด์ผ ํ๋์ง๋ฅผ ์ค๋ช
ํ๋ JSON ๋ฐ์ดํฐ๊ฐ ํฌํจ๋์ด ์๋ค. ์๋ฅผ ๋ค์ด, private ๋ฉ์๋์ Spring ์ด๋
ธํ
์ด์
์ ์ฌ์ฉํ ๊ฒฝ์ฐ Spring์ GraalVM์์๋ private ๋ฉ์๋๋ฅผ ํธ์ถํ๊ธฐ ์ํด ๋ฆฌํ๋ ์
์ ์ฌ์ฉํด์ผ ํ๋ค.
์ด๋ฌํ ์ํฉ์ด ๋ฐ์ํ๋ฉด Spring์ ๋ฆฌํ๋ ์
ํํธ๋ฅผ ์์ฑํ์ฌ private ๋ฉ์๋๊ฐ ์ง์ ํธ์ถ๋์ง ์๋๋ผ๋ ๋ค์ดํฐ๋ธ ์ด๋ฏธ์ง์์ ์ฌ์ฉํ ์ ์์ด์ผ ํ๋ค๋ ๊ฒ์ GraalVM์ด ์ ์ ์๋๋ก ํ๋ค. ํํธ ํ์ผ์ target/spring-aot/main/resources/META-INF/native-image์ ์์ฑ๋๋ฉฐ GraalVM์์ ์๋์ผ๋ก ๊ฐ์ ธ์จ๋ค.
์์ฑ๋ ํํธ ํ์ผ์ ์์ฑ ๊ฒฝ๋ก๋ ์๋์ ๊ฐ๋ค.
- Maven
- target/spring-aot/main/resources
- Gradle
- build/generated/aotResources

Spring Boot GraalVM Proxy Class Generation
Spring์ ์ถ๊ฐ ๊ธฐ๋ฅ์ผ๋ก ์์ฑํ ์ฝ๋๋ฅผ ํฅ์์ํค๊ธฐ ์ํด ํ๋ก์ ํด๋์ค๋ฅผ ์์ฑํ๋ค. ์ด๋ฅผ ์ํด ๋ฐ์ดํธ์ฝ๋๋ฅผ ์ง์ ์์ฑํ๋ cglib ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ค. ์ ํ๋ฆฌ์ผ์ด์
์ด JVM์์ ์คํ๋ ๋ ํ๋ก์ ํด๋์ค๋ ์ ํ๋ฆฌ์ผ์ด์
์ด ์คํ๋จ์ ๋ฐ๋ผ ๋์ ์ผ๋ก ์์ฑ๋๋ค. ๋ค์ดํฐ๋ธ ์ด๋ฏธ์ง๋ฅผ ์์ฑํ ๋ ์ด๋ฌํ ํ๋ก์ ํด๋์ค๋ ๋น๋ ํ์์ ์์ฑํด์ผ GraalVM์ ํฌํจ๋ ์ ์๋ค. ์์ค ์ฝ๋ ์์ฑ๊ณผ ๋ฌ๋ฆฌ ์์ฑ๋ ๋ฐ์ดํธ์ฝ๋๋ ์ ํ๋ฆฌ์ผ์ด์
์ ๋๋ฒ๊น
ํ ๋ ํน๋ณํ ์ ์ฉํ์ง ์๋ค.
๊ทธ๋ฌ๋ javap์ ๊ฐ์ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ฌ .class ํ์ผ์ ๋ด์ฉ์ ๊ฒ์ฌํด์ผ ํ๋ ๊ฒฝ์ฐ
maven์ target/spring-aot/main/classes, gradle์ build/generated/aotClasses ์์ ํด๋น ํ์ผ์ ์ฐพ์ ์ ์๋ค.
Spring Boot GraalVM ๋ค์ดํฐ๋ธ ์ ํ๋ฆฌ์ผ์ด์ ๊ฐ๋ฐํ๊ธฐ
๋ค์ดํฐ๋ธ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋น๋ํ๋ ๋ฐฉ๋ฒ์๋ ํฌ๊ฒ ๋๊ฐ์ง ๋ฐฉ๋ฒ์ด ์๋ค.
- Spring Boot์์ ์ง์ํ๋ cloud native buildpack์ ์ด์ฉํ์ฌ ๋ค์ดํฐ๋ธ
์คํํ์ผ์ด ํฌํจ๋ ๊ฒฝ๋ ์ปจํ ์ด๋๋ฅผ ์์ฑํ๋ ๋ฐฉ๋ฒ - GraalVM ๋ค์ดํฐ๋ธ ๋น๋ ํด์ ์ฌ์ฉํ์ฌ ๋ค์ดํฐ๋ธ ์คํ ํ์ผ์ ์์ฑํ๋ ๋ฐฉ๋ฒ
์๋ก์ด native spring boot ํ๋ก์ ํธ๋ฅผ ์์ํ๋ ๊ฐ์ฅ ์ฌ์ด ๋ฐฉ๋ฒ์ start.spring.io ์ฌ์ดํธ์์ ‘GraalVM Native Support’ ์ข
์์ฑ์ ์ถ๊ฐํ์ฌ ํ๋ก์ ํธ๋ฅผ ์์ฑํ๋ ๊ฒ์ด๋ค. ํฌํจ๋ HELP.md ํ์ผ์ ์์ ํํธ๋ฅผ ์ ๊ณตํ๋ค.
์๋์ ๊ฐ์ ๊ธฐ๋ณธ ์ ํ๋ฆฌ์ผ์ด์
์ฝ๋๊ฐ ์๋ค.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@SpringBootApplication
public class MyApplication {
@RequestMapping("/")
String home() {
return "Hello World!";
}
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}JavaBuildPacks ๋ฅผ ์ด์ฉํ์ฌ Native Image ๋น๋ํ๊ธฐ
Spring Boot์๋ maven๊ณผ gradle ๋ชจ๋์ ๋ํด์ ๋ค์ดํฐ๋ธ ์ด๋ฏธ์ง์ ๋ํ ๋น๋ํฉ ์ง์์ด ํฌํจ๋์ด ์๋ค. ๋ช
๋ น์ด ํ๋๋ง ์
๋ ฅํ๋ฉด ๋ก์ปฌ์์ ์คํ ์ค์ธ Docker ๋ฐ๋ชฌ์ ์ ์ ํ ์ด๋ฏธ์ง๋ฅผ ๋น ๋ฅด๊ฒ ๊ฐ์ ธ์ฌ ์ ์๋ค. ๊ฒฐ๊ณผ ์ด๋ฏธ์ง์๋ JVM์ด ํฌํจ๋์ง ์๊ณ ๋ค์ดํฐ๋ธ ์ด๋ฏธ์ง๊ฐ ์ ์ ์ผ๋ก ์ปดํ์ผ๋๋ค. JVM์ด ํฌํจ๋์ง ์๊ธฐ ๋๋ฌธ์ ์ปจํ
์ด๋ ์ด๋ฏธ์ง ํฌ๊ธฐ๋ ๋ ์์์ง๋ค.
๋น๋๋ฅผ ์ํด์ ์ฌ์ฉ๋๋ ์ด๋ฏธ์ง๋ paketobuildpacks/builder:tiny ์ด๋ค. ๋น๋๋ฅผ ์ํ ์ด๋ฏธ์ง์ ๋ ๋ง์ ํด์ ์ฌ์ฉํ๊ธฐ ์ํด์๋ paketobuildpacks/builder-jammy-base ํน์ paketobuildpacks/builder-jammy-full์ ์ฌ์ฉํ ์๋ ์๋ค.
์ด ๋ฐฉ๋ฒ์ Docker ๋ฐ๋ชฌ์ด ์ค์น๋์ด ์์ด์ผ ํ๋ค.
macOS ์์๋ Docker์ ํ ๋น๋ ๋ฉ๋ชจ๋ฆฌ๋ฅผ 8GB ์ด์์ผ๋ก ๋๋ฆฌ๊ณ CPU๋ ๋ ์ถ๊ฐํ ๊ฒ์ ๊ถ์ฅํ๋ค.
Docker Desktop ์์ ์ค์ > Resources > Advanced ํญ๋ชฉ์์ ์ค์ ํ ์ ์๋ค.
Windows์์๋ ๋ ๋์ ์ฑ๋ฅ์ ์ํด Docker WSL2 ๋ฐฑ์๋๋ฅผ ์ฌ์ฉํ๋๋ก ์ค์ ํด์ผ ํ๋ค.
maven์ ์ฌ์ฉํ์ฌ native ์ด๋ฏธ์ง ์ปจํ ์ด๋ ๋น๋
maven์ ์ฌ์ฉํ์ฌ native ์ด๋ฏธ์ง ์ปจํ
์ด๋๋ฅผ ๋น๋ํ๋ ค๋ฉด pom.xml ํ์ผ์ spring-boot-starter-parent ๋ฐ org.graalvm.buildtools:native-maven-plugin ์ด ์ฌ์ฉ๋๋๋ก ํด์ผ ํ๋ค.
์๋์ ๊ฐ์ <parent> ์น์
์ด ์์ด์ผ ํ๋ค.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.3</version>
</parent>XMLspring-boot-starter-parent ์ pom ํ์ผ์ ๋ณด๋ฉด <profiles> ์น์ ์ ์๋์ ๊ฐ์ด native profile ์ด ์ ์๋์ด ์๋ค.
<profile>
<id>native</id>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Spring-Boot-Native-Processed>true</Spring-Boot-Native-Processed>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<image>
<builder>paketobuildpacks/builder:tiny</builder>
<env>
<BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE>
</env>
</image>
</configuration>
<executions>
<execution>
<id>process-aot</id>
<goals>
<goal>process-aot</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<configuration>
<classesDirectory>${project.build.outputDirectory}</classesDirectory>
<metadataRepository>
<enabled>true</enabled>
</metadataRepository>
<requiredVersion>22.3</requiredVersion>
</configuration>
<executions>
<execution>
<id>add-reachability-metadata</id>
<goals>
<goal>add-reachability-metadata</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
</profile>XML<build><plugins> ์น์ ์ ์๋์ ๊ฐ์ ํ๋ฌ๊ทธ์ธ์ด ์ถ๊ฐ๋์ด์ผ ํ๋ค.
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
</plugin>XMLspring-boot-starter-parent๋ ๋ค์ดํฐ๋ธ ์ด๋ฏธ์ง๋ฅผ ์์ฑํ๊ธฐ ์ํด ์คํํด์ผ ํ๋ ์คํ์ ๊ตฌ์ฑํ๋ ๋ค์ดํฐ๋ธ ํ๋กํ์ผ์ ์ ์ธํ๋ค. ๋ช
๋ น์ค์์ -P ํ๋๊ทธ๋ฅผ ์ฌ์ฉํ์ฌ ํ๋กํ์ผ์ ํ์ฑํ ํ ์ ์๋ค.
spring-boot-starter-parent๋ฅผ ์ฌ์ฉํ์ง ์์ผ๋ ค๋ฉด Spring Boot ํ๋ฌ๊ทธ์ธ์ process-aot goal ๊ณผ ๋ค์ดํฐ๋ธ ๋น๋ ๋๊ตฌ ํ๋ฌ๊ทธ์ธ์์ add-reachability-metadata goal์ ๊ตฌ์ฑํด์ผ ํ๋ค.
native ์ด๋ฏธ์ง๊ฐ ํฌํจ๋ ์ปจํ
์ด๋ ์ด๋ฏธ์ง๋ฅผ ๋น๋ํ๋ ค๋ฉด native ํ๋กํ์ด ํ์ฑํ๋ ์ํ์์ spring-boot:build-image ๋ฅผ ์คํํ๋ค.
$> mvn -Pnative spring-boot:build-imageBashGradle์ ์ฌ์ฉํ์ฌ native ์ด๋ฏธ์ง ์ปจํ ์ด๋ ๋น๋
Spring Boot Gradle ํ๋ฌ๊ทธ์ธ์ GraalVM ๋ค์ดํฐ๋ธ ์ด๋ฏธ์ง ํ๋ฌ๊ทธ์ธ์ด ์ ์ฉ๋ ๋ AOT ์์
์ ์๋์ผ๋ก ๊ตฌ์ฑํ๋ค. build.gradle ํ์ผ์์ ํ๋ฌ๊ทธ์ธ ๋ธ๋ก์์ org.graalvm.buildtools.native๊ฐ ํฌํจ๋์ด์ผ ํ๋ค.
org.graalvm.buildtools.native ํ๋ฌ๊ทธ์ธ์ด ์ ์ฉ๋์ด ์๋ ํ bootBuildImage ์์
์ JVM ์ด๋ฏธ์ง๊ฐ ์๋ ๋ค์ดํฐ๋ธ ์ด๋ฏธ์ง ํฌํจํ ์ปจํ
์ด๋ ์ด๋ฏธ์ง๋ฅผ ์์ฑํ๋ค.
$> gradle bootBuildImage Bash์๋ ๋ช ๋ น์ผ๋ก ๋น๋๋ ์ด๋ฏธ์ง๋ฅผ docker ํ๊ฒฝ์์ ์คํํ ์ ์๋ค.
$> docker run --rm -p 8080:8080 docker.io/library/myproject:0.0.1-SNAPSHOT BashNative Build Tools ๋ฅผ ์ฌ์ฉํ์ฌ Native ์ด๋ฏธ์ง ๋น๋ํ๊ธฐ
Docker ๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ๋ค์ดํฐ๋ธ ์คํ ํ์ผ์ ์ง์ ์์ฑํ๋ ค๋ฉด GraalVM ๋ค์ดํฐ๋ธ ๋น๋ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ ์ ์๋ค. ๋ค์ดํฐ๋ธ ๋น๋ ๋๊ตฌ๋ maven๊ณผ gradle ๋ชจ๋๋ฅผ ์ํด GraalVM์์ ์ ๊ณตํ๋ ํ๋ฌ๊ทธ์ธ์ด๋ค. ๋ค์ดํฐ๋ธ ๋น๋ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ฌ ๋ค์ดํฐ๋ธ ์ด๋ฏธ์ง ์์ฑ์ ๋น๋กฏํ ๋ค์ํ GraalVM์์ ์ ์ํํ ์ ์๋ค. ์ฌ๊ธฐ์ ๋งํ๋ ๋ค์ดํฐ๋ธ ์ด๋ฏธ์ง๋ ์ปจํ ์ด๋ ์ด๋ฏธ์ง๊ฐ ์๋ ์คํํ์ผ์ด๋ผ๊ณ ์๊ฐํ๋ฉด ๋๊ฒ ๋ค.
์ฌ์ ์กฐ๊ฑด
๋ค์ดํฐ๋ธ ๋น๋ ํด์ ์ฌ์ฉํ์ฌ ๋ค์ดํฐ๋ธ ์ด๋ฏธ์ง๋ฅผ ๋น๋ํ๋ ค๋ฉด ๋จธ์ ์ GraalVM ๋ฐฐํฌํ์ด ํ์ํ๋ค.
Liberica Native Image Kit page ์์ ์๋์ผ๋ก ๋ค์ด๋ก๋ ํ์ฌ ์ค์นํ๊ฑฐ๋ SDKMAN๊ณผ ๊ฐ์ SDK ๊ด๋ฆฌ์ ๋๊ตฌ๋ฅผ์ฌ์ฉํ์ฌ ์ค์นํ ์ ์๋ค.
SDKMAN ์ค์น ๋ฐ ์ฌ์ฉ๋ฒ์ ์๋ ํฌ์คํ
์ ์ฐธ๊ณ ํ๊ธฐ ๋ฐ๋๋ค.
SDKMAN์ผ๋ก ๊ฐ๋ฐ๋๊ตฌ ๋ฒ์ ์ฝ๊ฒ ๊ด๋ฆฌํ์
macOS ํน์ ๋ฆฌ๋
์ค ํ๊ฒฝ์์๋ SDKMAN ์ ์ฌ์ฉํ์ฌ ๋ค์ดํฐ๋ธ ์ด๋ฏธ์ง ์ปดํ์ผ๋ฌ๋ฅผ ์ค์นํ๋ ๊ฒ์ด ํธํ๋ค. SDKMAN์ ์ค์น ํ ์๋ ๋ช
๋ น์ ์ฌ์ฉํ์ฌ GraalVM ๋ฐฐํฌ๋ฅผ ์ค์นํ๋ค.
-nik ๋ Liberica ์์ ์ ๊ณตํ๋ Native Image Kit ์ ์ฝ์์ด๋ค.
$> sdk install java 22.3.3.r17-nik
$> sdk use java 22.3.3.r17-nik
Using java version 22.3.3.r17-nik in this shell.
$> java -version
openjdk version "17.0.8" 2023-07-18 LTS
OpenJDK Runtime Environment GraalVM 22.3.3 (build 17.0.8+7-LTS)
OpenJDK 64-Bit Server VM GraalVM 22.3.3 (build 17.0.8+7-LTS, mixed mode, sharing) Bash์ฃผ์ ํ ๊ฒ์ sdk use ๋ช ๋ น์ผ๋ก java ์ ๋ฒ์ ์ 22.3.3.r17-nik ํจํค์ง ๋ฒ์ ์ผ๋ก ๋ณ๊ฒฝํ์์ง๋ง ํด๋น ์์๋ง ์ ์ฉ๋๋ค๋ ๊ฒ์ด๋ค. ์๊ตฌ์ ์ผ๋ก ๋ณ๊ฒฝํ๋ ค๋ฉด ์๋ ๋ช ๋ น์ ์ฌ์ฉํ๋ค.
$> sdk default java 22.3.3.r17-nik Bash์๋์ฐ์ฆ์ ๊ฒฝ์ฐ์๋ native image for window ๋ฅผ ์ฐธ๊ณ ํ๋ค.
Maven
Spring Boot buildpack ์ง์๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ๋ค์ดํฐ๋ธ ํ๋กํ์ผ์ ์์ํ๋ ค๋ฉด pom.xml์์ spring-boot-starter-parent๋ฅผ ์ฌ์ฉํ๊ณ org.graalvm.buildtools:native-maven-plugin ์ ์ถ๊ฐํด์ผ ํ๋ค.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.3</version>
</parent>XML<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
</plugin>XML์๋ ๋ช ๋ น์ผ๋ก ๋น๋ํ๋ฉด target ๋๋ ํ ๋ฆฌ์์ native ์ด๋ฏธ์ง ์คํ ํ์ผ์ ์ฐพ์ ์ ์๋ค.
$> mvn -Pnative native:compile Bash$> file target/<์คํํ์ผ๋ช
>
ex)
$> file target/rest-doc
target/rest-doc: Mach-O 64-bit executable arm64 Bashfile ๋ช ๋ น์ผ๋ก ์คํํ์ผ์์ ํ์ธํ ์ ์๋ค.
Gradle
Native Build Tools Gradle ํ๋ฌ๊ทธ์ธ์ด gradle ํ๋ก์ ํธ์ ์ ์ฉ๋๋ฉด Spring Boot Gradle ํ๋ฌ๊ทธ์ธ์ด ์๋์ผ๋ก Spring AOT ์์ง์ ํธ๋ฆฌ๊ฑฐ ํ๋ค. task ์ข ์์ฑ์ด ์๋์ผ๋ก ๊ตฌ์ฑ๋๋ฏ๋ก ํ์ค nativeCompile task ๋ฅผ ์คํํ์ฌ ๋ค์ดํฐ๋ธ ์ด๋ฏธ์ง๋ฅผ ์์ฑํ๋ค.
$> gradle nativeCompileBashnative ์ด๋ฏธ์ง ์คํ ํ์ผ์ build/native/nativeCompile ๋๋ ํ ๋ฆฌ์์ ์ฐพ์ ์ ์๋ค.
์คํ์๋๋ ํ์คํ GraalVM์ผ๋ก ๋น๋ํ ๋ฐ์ด๋๋ฆฌ๊ฐ ๋น ๋ฅธ๋ฏ ํ๋ค.
native ์ด๋ฏธ์ง ์คํ
2023-09-04T00:16:55.602+09:00 INFO 8824 --- [ main] com.example.restdoc.RestDocApplication : Starting AOT-processed RestDocApplication using Java 17.0.8 with PID 8824
2023-09-04T00:16:55.602+09:00 INFO 8824 --- [ main] com.example.restdoc.RestDocApplication : No active profile set, falling back to 1 default profile: "default"
2023-09-04T00:16:55.620+09:00 INFO 8824 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2023-09-04T00:16:55.621+09:00 INFO 8824 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2023-09-04T00:16:55.621+09:00 INFO 8824 --- [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.10]
2023-09-04T00:16:55.627+09:00 INFO 8824 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2023-09-04T00:16:55.627+09:00 INFO 8824 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 24 ms
2023-09-04T00:16:55.665+09:00 INFO 8824 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2023-09-04T00:16:55.665+09:00 INFO 8824 --- [ main] com.example.restdoc.RestDocApplication : Started RestDocApplication in 0.081 seconds (process running for 0.098)
Plaintextjava ์ดํ๋ฆฌ์ผ์ด์ ์คํ
2023-09-04T00:18:12.410+09:00 INFO 8926 --- [ restartedMain] com.example.restdoc.RestDocApplication : Starting RestDocApplication using Java 17.0.6 with PID 8926
2023-09-04T00:18:12.411+09:00 INFO 8926 --- [ restartedMain] com.example.restdoc.RestDocApplication : No active profile set, falling back to 1 default profile: "default"
2023-09-04T00:18:12.430+09:00 INFO 8926 --- [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable
2023-09-04T00:18:12.431+09:00 INFO 8926 --- [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : For additional web related logging consider setting the 'logging.level.web' property to 'DEBUG'
2023-09-04T00:18:12.765+09:00 INFO 8926 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2023-09-04T00:18:12.769+09:00 INFO 8926 --- [ restartedMain] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2023-09-04T00:18:12.769+09:00 INFO 8926 --- [ restartedMain] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.10]
2023-09-04T00:18:12.790+09:00 INFO 8926 --- [ restartedMain] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2023-09-04T00:18:12.791+09:00 INFO 8926 --- [ restartedMain] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 359 ms
2023-09-04T00:18:12.952+09:00 INFO 8926 --- [ restartedMain] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729
2023-09-04T00:18:12.964+09:00 INFO 8926 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2023-09-04T00:18:12.969+09:00 INFO 8926 --- [ restartedMain] com.example.restdoc.RestDocApplication : Started RestDocApplication in 0.703 seconds (process running for 0.968)
Plaintext์์ ์๋๊ฐ ์ฝ 9๋ฐฐ ๊ฐ๋ ์ฐจ์ด๊ฐ ๋จ์ ์ ์ ์๋ค.
์ง๊ธ๊น์ง Spring Boot ์์ ์ง์ํ๋ GraalVM ๋น๋ ๋๊ตฌ๋ฅผ ์ด์ฉํ native ์ด๋ฏธ์ง๋ฅผ ๋น๋ ํ๋ ๋ฐฉ๋ฒ์ ๋ํด์ ๊ณต์ ๋ฌธ์๋ฅผ ์ ๋ฆฌํด ๋ณด์๋ค. ์๋ ๊ด๋ จ ๋งํฌ๋ฅผ ์ฐธ๊ณ ํ๋ฉด ๋ง์ ๋์์ด ๋ ๊ฒ ๊ฐ๋ค.
๊ด๋ จ๋งํฌ
https://docs.spring.io/spring-boot/docs/current/reference/html/native-image.html#native-image.introducing-graalvm-native-images
https://www.graalvm.org/22.3/reference-manual/native-image/
