#spring #spring-boot #graalvm #graalvm-native-image
#spring #весенняя загрузка #graalvm #graalvm-native-image
Вопрос:
У меня есть приложение spring boot 2.3, которое я хочу скомпилировать как собственный образ.
Я использую GraalVM 20.1.0.r11-grl
в качестве SDK / JDK, и мое приложение компилируется и работает нормально. Я использую Gradle для своего инструмента сборки и использую https://github.com/ayltai/spring-graalvm-native-plugin для доступа к функциональности встроенного образа — это работает хорошо.
Когда я пытаюсь скомпилировать собственный образ, я получаю следующую трассировку стека (оригинал длиной около 900 строк в подробном режиме, поэтому я пытаюсь выделить соответствующие биты):
WARNING: Could not register reflection metadata for org.springframework.boot.actuate.autoconfigure.endpoint.web.reactive.WebFluxEndpointManagementContextConfiguration. Reason: java.lang.NoClassDefFoundError: org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerMapping.
WARNING: Could not register reflection metadata for org.springframework.boot.actuate.autoconfigure.web.jersey.JerseySameManagementContextConfiguration. Reason: java.lang.NoClassDefFoundError: org/glassfish/jersey/server/ResourceConfig.
[valuable-api:14937] analysis: 53,754.65 ms, 3.98 GB
Fatal error:com.oracle.graal.pointsto.util.AnalysisError$ParsingError: Error encountered while parsing org.springframework.hateoas.config.WebFluxHateoasConfiguration$WebFluxCodecs.getDecoder(com.fasterxml.jackson.databind.ObjectMapper, java.util.List)
Parsing context:
parsing com.oracle.svm.reflect.WebFluxHateoasConfiguration$WebFluxCodecs_getDecoder_ebe8383216b03b797b6e4dde145c81aea1634443_11905.invoke(Unknown Source)
parsing java.lang.reflect.Method.invoke(Method.java:566)
parsing org.springframework.core.convert.support.ObjectToObjectConverter.convert(ObjectToObjectConverter.java:102)
parsing org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:41)
parsing org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:191)
parsing org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:174)
parsing org.springframework.core.env.AbstractPropertyResolver.convertValueIfNecessary(AbstractPropertyResolver.java:265)
parsing org.springframework.core.env.PropertySourcesPropertyResolver.getProperty(PropertySourcesPropertyResolver.java:91)
parsing org.springframework.core.env.PropertySourcesPropertyResolver.getProperty(PropertySourcesPropertyResolver.java:62)
parsing org.springframework.core.env.AbstractPropertyResolver.getProperty(AbstractPropertyResolver.java:169)
parsing org.springframework.core.env.AbstractEnvironment.getProperty(AbstractEnvironment.java:540)
parsing org.springframework.boot.SpringApplicationBannerPrinter.createStringFromBanner(SpringApplicationBannerPrinter.java:116)
parsing org.springframework.boot.SpringApplicationBannerPrinter.print(SpringApplicationBannerPrinter.java:61)
parsing org.springframework.boot.SpringApplication.printBanner(SpringApplication.java:556)
parsing org.springframework.boot.SpringApplication.run(SpringApplication.java:310)
parsing org.springframework.boot.SpringApplication.run(SpringApplication.java:1237)
parsing org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)
parsing nz.ringfence.valuable.api.ValuableApiApplication.main(ValuableApiApplication.java:11)
parsing com.oracle.svm.core.JavaMainWrapper.runCore(JavaMainWrapper.java:149)
parsing com.oracle.svm.core.JavaMainWrapper.run(JavaMainWrapper.java:184)
parsing com.oracle.svm.core.code.IsolateEnterStub.JavaMainWrapper_run_5087f5482cc9a6abc971913ece43acb471d2631b(generated:0)
at com.oracle.graal.pointsto.util.AnalysisError.parsingError(AnalysisError.java:138)
at com.oracle.graal.pointsto.flow.MethodTypeFlow.doParse(MethodTypeFlow.java:336)
at com.oracle.graal.pointsto.flow.MethodTypeFlow.ensureParsed(MethodTypeFlow.java:311)
at com.oracle.graal.pointsto.flow.MethodTypeFlow.addContext(MethodTypeFlow.java:112)
at com.oracle.graal.pointsto.flow.StaticInvokeTypeFlow.update(InvokeTypeFlow.java:437)
at com.oracle.graal.pointsto.BigBang$2.run(BigBang.java:530)
at com.oracle.graal.pointsto.util.CompletionExecutor.lambda$execute$0(CompletionExecutor.java:173)
at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1426)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:177)
Caused by: org.graalvm.compiler.java.BytecodeParser$BytecodeParserError: java.lang.NoClassDefFoundError: org/reactivestreams/Publisher
at parsing org.springframework.hateoas.config.WebFluxHateoasConfiguration$WebFluxCodecs.getDecoder(WebFluxHateoasConfiguration.java:123)
at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.throwParserError(BytecodeParser.java:2590)
at com.oracle.svm.hosted.phases.SharedGraphBuilderPhase$SharedBytecodeParser.throwParserError(SharedGraphBuilderPhase.java:94)
at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.iterateBytecodesForBlock(BytecodeParser.java:3428)
at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.processBlock(BytecodeParser.java:3230)
at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.build(BytecodeParser.java:1088)
at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.buildRootMethod(BytecodeParser.java:982)
at jdk.internal.vm.compiler/org.graalvm.compiler.java.GraphBuilderPhase$Instance.run(GraphBuilderPhase.java:84)
at jdk.internal.vm.compiler/org.graalvm.compiler.phases.Phase.run(Phase.java:49)
at jdk.internal.vm.compiler/org.graalvm.compiler.phases.BasePhase.apply(BasePhase.java:214)
at jdk.internal.vm.compiler/org.graalvm.compiler.phases.Phase.apply(Phase.java:42)
at jdk.internal.vm.compiler/org.graalvm.compiler.phases.Phase.apply(Phase.java:38)
at com.oracle.graal.pointsto.flow.MethodTypeFlowBuilder.parse(MethodTypeFlowBuilder.java:225)
at com.oracle.graal.pointsto.flow.MethodTypeFlowBuilder.apply(MethodTypeFlowBuilder.java:352)
at com.oracle.graal.pointsto.flow.MethodTypeFlow.doParse(MethodTypeFlow.java:322)
... 11 more
Caused by: java.lang.NoClassDefFoundError: org/reactivestreams/Publisher
at jdk.internal.vm.ci/jdk.vm.ci.hotspot.CompilerToVM.getDeclaredMethods(Native Method)
at jdk.internal.vm.ci/jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl.getDeclaredMethods(HotSpotResolvedObjectTypeImpl.java:958)
at com.oracle.svm.hosted.classinitialization.ClassInitializationFeature.declaresDefaultMethods(ClassInitializationFeature.java:385)
at com.oracle.svm.hosted.classinitialization.ConfigurableClassInitialization.processInterfaces(ConfigurableClassInitialization.java:606)
at com.oracle.svm.hosted.classinitialization.ConfigurableClassInitialization.computeInitKindAndMaybeInitializeClass(ConfigurableClassInitialization.java:565)
at com.oracle.svm.hosted.classinitialization.ConfigurableClassInitialization.computeInitKindAndMaybeInitializeClass(ConfigurableClassInitialization.java:132)
at com.oracle.svm.hosted.classinitialization.ConfigurableClassInitialization.maybeInitializeHosted(ConfigurableClassInitialization.java:160)
at com.oracle.svm.hosted.SVMHost.registerType(SVMHost.java:223)
at com.oracle.graal.pointsto.meta.AnalysisUniverse.createType(AnalysisUniverse.java:264)
at com.oracle.graal.pointsto.meta.AnalysisUniverse.lookupAllowUnresolved(AnalysisUniverse.java:205)
at com.oracle.graal.pointsto.meta.AnalysisUniverse.lookup(AnalysisUniverse.java:182)
at com.oracle.graal.pointsto.meta.AnalysisType.convertTypes(AnalysisType.java:209)
at com.oracle.graal.pointsto.meta.AnalysisType.<init>(AnalysisType.java:169)
at com.oracle.graal.pointsto.meta.AnalysisUniverse.createType(AnalysisUniverse.java:263)
at com.oracle.graal.pointsto.meta.AnalysisUniverse.lookupAllowUnresolved(AnalysisUniverse.java:205)
at com.oracle.graal.pointsto.meta.AnalysisUniverse.lookup(AnalysisUniverse.java:182)
at com.oracle.graal.pointsto.meta.AnalysisType.<init>(AnalysisType.java:168)
at com.oracle.graal.pointsto.meta.AnalysisUniverse.createType(AnalysisUniverse.java:263)
at com.oracle.graal.pointsto.meta.AnalysisUniverse.lookupAllowUnresolved(AnalysisUniverse.java:205)
at com.oracle.graal.pointsto.infrastructure.WrappedConstantPool.lookupType(WrappedConstantPool.java:155)
at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.lookupType(BytecodeParser.java:4274)
at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.genNewInstance(BytecodeParser.java:4545)
at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.processBytecode(BytecodeParser.java:5343)
at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.iterateBytecodesForBlock(BytecodeParser.java:3423)
... 22 more
Caused by: java.lang.ClassNotFoundException: org.reactivestreams.Publisher
at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:471)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:589)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
... 46 more
Error: Image build request failed with exit status 1
com.oracle.svm.driver.NativeImage$NativeImageError: Image build request failed with exit status 1
at com.oracle.svm.driver.NativeImage.showError(NativeImage.java:1541)
at com.oracle.svm.driver.NativeImage.build(NativeImage.java:1299)
at com.oracle.svm.driver.NativeImage.performBuild(NativeImage.java:1260)
at com.oracle.svm.driver.NativeImage.main(NativeImage.java:1219)
at com.oracle.svm.driver.NativeImage$JDK9Plus.main(NativeImage.java:1722)
Похоже, эта ошибка возникает из-за того, что Native Image считает, что у меня есть компонент WebFlux в моем пути к классам, и когда он попытался обработать этот компонент, он не может его найти, отсюда ClassNotFoundException
внизу трассировки.
Вот мои зависимости:
// Spring Boot
implementation('org.springframework.boot:spring-boot-starter-actuator')
implementation('org.springframework.boot:spring-boot-starter-data-jpa')
implementation('org.springframework.hateoas:spring-hateoas:1.1.1.RELEASE')
implementation('org.springframework.boot:spring-boot-starter-web')
implementation('org.springframework.boot:spring-boot-starter-security')
implementation('org.springframework.boot:spring-boot-starter-aop')
implementation('org.springframework.boot:spring-boot-starter-validation')
runtimeOnly('org.springframework.boot:spring-boot-devtools')
annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"
// Native Image
implementation('org.springframework:spring-context-indexer')
implementation('org.springframework.experimental:spring-graalvm-native:0.7.1')
// Testing
testImplementation('org.junit.jupiter:junit-jupiter-api:5.3.1')
testRuntimeOnly('org.junit.jupiter:junit-jupiter-engine:5.3.1')
testImplementation('org.springframework.boot:spring-boot-starter-test')
testImplementation("org.assertj:assertj-core:3.12.0")
testImplementation 'org.mockito:mockito-core:2. '
testImplementation "org.springframework.security:spring-security-test"
testImplementation 'com.intuit.karate:karate-junit5:0.9.5'
testImplementation 'com.intuit.karate:karate-apache:0.9.5'
testImplementation "net.masterthought:cucumber-reporting:3.8.0"
// Persistence
implementation('com.h2database:h2')
implementation('org.postgresql:postgresql')
implementation('org.springframework.boot:spring-boot-starter-jdbc')
implementation "org.flywaydb:flyway-core"
// Swagger
implementation 'org.springdoc:springdoc-openapi-ui:1.3.0'
// Observability
implementation 'io.sentry:sentry-spring:1.7.30'
implementation 'io.honeycomb.beeline:beeline-spring-boot-starter:1.2.0'
implementation 'nl.basjes.parse.useragent:yauaa:5.18'
// Security
implementation 'com.auth0:auth0-spring-security-api:1.3.1'
implementation 'org.springframework.security:spring-security-oauth2-resource-server'
implementation 'org.springframework.security:spring-security-oauth2-jose'
implementation 'org.springframework.security:spring-security-config'
// Outgoing Email
implementation 'com.sendgrid:sendgrid-java:4.0.1'
Там нет реактивных компонентов. Единственное, о чем я могу думать, это о том, что где-то есть транзитивная зависимость, но не имеет смысла, что нереактивный компонент будет иметь транзитивную зависимость?
У кого-нибудь раньше была эта проблема? Как я могу отладить и исправить это?
Комментарии:
1. Да, я сильно столкнулся с этими ошибками во время работы над blog.codecentric.de/en/2020/05/spring-boot-graalvm — тогда у меня было два «варианта»: просто попытаться использовать агент собственного образа, чтобы попытаться сгенерировать рабочую конфигурацию для процесса сборки — или это просто не сработало прямо сейчас, поскольку
spring-graal-native
проект не поддерживал компонент, который я использовал до этого момента. Поскольку на прошлой неделе произошла Spring One 2020, я не уверен, что0.7.1
этого достаточно для использованияspring-boot-starter-jdbc
, посколькуJDBC
будет поддерживаться только из0.8.x
.2. Пытаюсь ответить на ваш конкретный вопрос: вы сами явно не полагаетесь на Webflux /
spring-boot-starter-webflux
зависимость, но взгляните на трассировку стека:Error encountered while parsing org.springframework.hateoas.config.WebFluxHateoasConfiguration$WebFluxCodecs
кажется, указывает нам на вашу зависимостьspring-hateoas
. Я бы заподозрил, что этот dep использует классы WebFlux…3. Кроме того, я думаю, что вы пытаетесь сделать, это захватить существующее «полномасштабное» приложение Spring Boot и встроить его в собственный образ без особых хлопот ?! Я предполагаю, что это сложная работа прямо сейчас, поскольку поддержка GraalVM в Spring все еще находится на ранних стадиях и рассматривается
alpha
прямо сейчас. Я думаю, у вас есть варианты: Сократите ваше приложение до абсолютного минимума необходимых зависимостей и попробуйте взглянуть на конфигурацию примеров проектов spring-graal-native на GitHub — или просто дождитесь запланированного на декабрьbeta
выпуска spring-graal-native (или даже дождитесь весны следующего года).