使用 Cloud Firestore 时 Micronaut Native Image gRPC 错误

Micronaut Native Image gRPC error when using Cloud Firestore

我有一个基本的 Micronaut 应用程序,我正在将其构建为本机映像。我正在使用这些参数构建它:

  native-image \
  --no-server \
  -H:+TraceClassInitialization \
  -H:+ReportExceptionStackTraces \
  --enable-url-protocols=http,https \
  --enable-all-security-services \
  --report-unsupported-elements-at-runtime \
  --no-fallback \
  -H:ConfigurationFileDirectories=/home/app/sample-app/agent-config-dir \
  --report-unsupported-elements-at-runtime \
  --initialize-at-build-time=org.conscrypt,com.fasterxml.jackson,javax,org.slf4j \
  -jar myapp.jar

映像构建良好,我可以启动它,但在尝试访问 Firestore 时,出现此异常:

Message: Unsupported method of Unsafe
Path Taken: new $MailingListsApiDefinition$Intercepted([MailingListsApiService mailingListsApiService],BeanContext beanContext,Qualifier qualifier,Interceptor[] interceptors) --> new MailingListsApiServiceImpl(TokenGenerator tokenGenerator,[Firestore db],ObjectMapper objectMapper)
io.micronaut.context.exceptions.BeanInstantiationException: Error instantiating bean of type  [com.example.sampleapp.api.service.impl.MailingListsApiServiceImpl]

Message: Unsupported method of Unsafe
Path Taken: new $MailingListsApiDefinition$Intercepted([MailingListsApiService mailingListsApiService],BeanContext beanContext,Qualifier qualifier,Interceptor[] interceptors) --> new MailingListsApiServiceImpl(TokenGenerator tokenGenerator,[Firestore db],ObjectMapper objectMapper)
    at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1916)
    at io.micronaut.context.DefaultBeanContext.getScopedBeanForDefinition(DefaultBeanContext.java:2383)
    at io.micronaut.context.DefaultBeanContext.getBeanForDefinition(DefaultBeanContext.java:2298)
    at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:2270)
    at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:1240)
    at io.micronaut.context.AbstractBeanDefinition.getBeanForConstructorArgument(AbstractBeanDefinition.java:1013)
    at com.example.sampleapp.api.service.impl.$MailingListsApiServiceImplDefinition.build(Unknown Source)
    at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1889)
    at io.micronaut.context.DefaultBeanContext.createAndRegisterSingletonInternal(DefaultBeanContext.java:2635)
    at io.micronaut.context.DefaultBeanContext.createAndRegisterSingleton(DefaultBeanContext.java:2621)
    at io.micronaut.context.DefaultBeanContext.getBeanForDefinition(DefaultBeanContext.java:2296)
    at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:2270)
    at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:1240)
    at io.micronaut.context.AbstractBeanDefinition.getBeanForConstructorArgument(AbstractBeanDefinition.java:1013)
    at com.example.sampleapp.api.$$MailingListsApiDefinition$InterceptedDefinition.build(Unknown Source)
    at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1889)
    at io.micronaut.context.DefaultBeanContext.getScopedBeanForDefinition(DefaultBeanContext.java:2383)
    at io.micronaut.context.DefaultBeanContext.getBeanForDefinition(DefaultBeanContext.java:2298)
    at io.micronaut.context.DefaultBeanContext.access0(DefaultBeanContext.java:78)
    at io.micronaut.context.DefaultBeanContext.getTarget(DefaultBeanContext.java:426)
    at io.micronaut.context.DefaultBeanContext.invoke(DefaultBeanContext.java:469)
    at io.micronaut.web.router.AbstractRouteMatch.execute(AbstractRouteMatch.java:312)
    at io.micronaut.web.router.RouteMatch.execute(RouteMatch.java:118)
    at io.micronaut.http.server.netty.RoutingInBoundHandler.lambda$buildResultEmitter(RoutingInBoundHandler.java:1352)
    at io.reactivex.internal.operators.flowable.FlowableDefer.subscribeActual(FlowableDefer.java:35)
    at io.reactivex.Flowable.subscribe(Flowable.java:14918)
    at io.reactivex.Flowable.subscribe(Flowable.java:14868)
    at io.micronaut.core.async.publisher.Publishers.lambda$map(Publishers.java:196)
    at io.micronaut.http.server.context.ServerRequestContextFilter.lambda$doFilter[=11=](ServerRequestContextFilter.java:62)
    at io.reactivex.internal.operators.flowable.FlowableFromPublisher.subscribeActual(FlowableFromPublisher.java:29)
    at io.reactivex.Flowable.subscribe(Flowable.java:14918)
    at io.reactivex.Flowable.subscribe(Flowable.java:14868)
    at io.micronaut.http.server.netty.RoutingInBoundHandler.lambda$buildExecutableRoute(RoutingInBoundHandler.java:1056)
    at io.micronaut.web.router.DefaultUriRouteMatch.execute(DefaultUriRouteMatch.java:80)
    at io.micronaut.web.router.RouteMatch.execute(RouteMatch.java:118)
    at io.micronaut.http.server.netty.RoutingInBoundHandler.handleRouteMatch(RoutingInBoundHandler.java:686)
    at io.micronaut.http.server.netty.RoutingInBoundHandler.channelRead0(RoutingInBoundHandler.java:548)
    at io.micronaut.http.server.netty.RoutingInBoundHandler.channelRead0(RoutingInBoundHandler.java:143)
    at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:99)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:102)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:93)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.micronaut.http.netty.stream.HttpStreamsHandler.channelRead(HttpStreamsHandler.java:197)
    at io.micronaut.http.netty.stream.HttpStreamsServerHandler.channelRead(HttpStreamsServerHandler.java:121)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
    at io.netty.handler.codec.MessageToMessageCodec.channelRead(MessageToMessageCodec.java:111)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:93)
    at io.netty.handler.codec.http.HttpServerKeepAliveHandler.channelRead(HttpServerKeepAliveHandler.java:64)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.handler.flow.FlowControlHandler.dequeue(FlowControlHandler.java:191)
    at io.netty.handler.flow.FlowControlHandler.channelRead(FlowControlHandler.java:153)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436)
    at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:321)
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:295)
    at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:286)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
    at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:714)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:650)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:576)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
    at io.netty.util.concurrent.SingleThreadEventExecutor.run(SingleThreadEventExecutor.java:989)
    at io.netty.util.internal.ThreadExecutorMap.run(ThreadExecutorMap.java:74)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.lang.Thread.run(Thread.java:834)
    at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:517)
    at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:193)
Caused by: com.oracle.svm.core.jdk.UnsupportedFeatureError: Unsupported method of Unsafe
    at com.oracle.svm.core.util.VMError.unsupportedFeature(VMError.java:86)
    at jdk.internal.misc.Unsafe.staticFieldOffset(Unsafe.java:230)
    at sun.misc.Unsafe.staticFieldOffset(Unsafe.java:662)
    at io.grpc.netty.shaded.io.netty.util.internal.PlatformDependent0.run(PlatformDependent0.java:282)
    at java.security.AccessController.doPrivileged(AccessController.java:83)
    at io.grpc.netty.shaded.io.netty.util.internal.PlatformDependent0.<clinit>(PlatformDependent0.java:267)
    at com.oracle.svm.core.hub.ClassInitializationInfo.invokeClassInitializer(ClassInitializationInfo.java:350)
    at com.oracle.svm.core.hub.ClassInitializationInfo.initialize(ClassInitializationInfo.java:270)
    at java.lang.Class.ensureInitialized(DynamicHub.java:499)
    at io.grpc.netty.shaded.io.netty.util.internal.PlatformDependent.isAndroid(PlatformDependent.java:289)
    at io.grpc.netty.shaded.io.netty.util.internal.PlatformDependent.<clinit>(PlatformDependent.java:92)
    at com.oracle.svm.core.hub.ClassInitializationInfo.invokeClassInitializer(ClassInitializationInfo.java:350)
    at com.oracle.svm.core.hub.ClassInitializationInfo.initialize(ClassInitializationInfo.java:270)
    at java.lang.Class.ensureInitialized(DynamicHub.java:499)
    at io.grpc.netty.shaded.io.netty.util.AsciiString.<init>(AsciiString.java:223)
    at io.grpc.netty.shaded.io.netty.util.AsciiString.<init>(AsciiString.java:210)
    at io.grpc.netty.shaded.io.netty.util.AsciiString.cached(AsciiString.java:1401)
    at io.grpc.netty.shaded.io.netty.util.AsciiString.<clinit>(AsciiString.java:48)
    at com.oracle.svm.core.hub.ClassInitializationInfo.invokeClassInitializer(ClassInitializationInfo.java:350)
    at com.oracle.svm.core.hub.ClassInitializationInfo.initialize(ClassInitializationInfo.java:270)
    at java.lang.Class.ensureInitialized(DynamicHub.java:499)
    at io.grpc.netty.shaded.io.grpc.netty.Utils.<clinit>(Utils.java:72)
    at com.oracle.svm.core.hub.ClassInitializationInfo.invokeClassInitializer(ClassInitializationInfo.java:350)
    at com.oracle.svm.core.hub.ClassInitializationInfo.initialize(ClassInitializationInfo.java:270)
    at java.lang.Class.ensureInitialized(DynamicHub.java:499)
    at io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder.<clinit>(NettyChannelBuilder.java:74)
    at com.oracle.svm.core.hub.ClassInitializationInfo.invokeClassInitializer(ClassInitializationInfo.java:350)
    at com.oracle.svm.core.hub.ClassInitializationInfo.initialize(ClassInitializationInfo.java:270)
    at java.lang.Class.ensureInitialized(DynamicHub.java:499)
    at io.grpc.netty.shaded.io.grpc.netty.NettyChannelProvider.builderForAddress(NettyChannelProvider.java:37)
    at io.grpc.netty.shaded.io.grpc.netty.NettyChannelProvider.builderForAddress(NettyChannelProvider.java:23)
    at io.grpc.ManagedChannelBuilder.forAddress(ManagedChannelBuilder.java:39)
    at com.google.api.gax.grpc.InstantiatingGrpcChannelProvider.createSingleChannel(InstantiatingGrpcChannelProvider.java:280)
    at com.google.api.gax.grpc.InstantiatingGrpcChannelProvider.access00(InstantiatingGrpcChannelProvider.java:71)
    at com.google.api.gax.grpc.InstantiatingGrpcChannelProvider.createSingleChannel(InstantiatingGrpcChannelProvider.java:210)
    at com.google.api.gax.grpc.ChannelPool.create(ChannelPool.java:72)
    at com.google.api.gax.grpc.InstantiatingGrpcChannelProvider.createChannel(InstantiatingGrpcChannelProvider.java:217)
    at com.google.api.gax.grpc.InstantiatingGrpcChannelProvider.getTransportChannel(InstantiatingGrpcChannelProvider.java:200)
    at com.google.api.gax.rpc.ClientContext.create(ClientContext.java:156)
    at com.google.api.gax.rpc.ClientContext.create(ClientContext.java:123)
    at com.google.cloud.firestore.spi.v1.GrpcFirestoreRpc.<init>(GrpcFirestoreRpc.java:122)
    at com.google.cloud.firestore.FirestoreOptions$DefaultFirestoreRpcFactory.create(FirestoreOptions.java:90)
    at com.google.cloud.firestore.FirestoreOptions$DefaultFirestoreRpcFactory.create(FirestoreOptions.java:82)
    at com.google.cloud.ServiceOptions.getRpc(ServiceOptions.java:561)
    at com.google.cloud.firestore.FirestoreOptions.getFirestoreRpc(FirestoreOptions.java:385)
    at com.google.cloud.firestore.FirestoreImpl.<init>(FirestoreImpl.java:67)
    at com.google.cloud.firestore.FirestoreOptions$DefaultFirestoreFactory.create(FirestoreOptions.java:73)
    at com.google.cloud.firestore.FirestoreOptions$DefaultFirestoreFactory.create(FirestoreOptions.java:66)
    at com.google.cloud.ServiceOptions.getService(ServiceOptions.java:541)
    at com.google.firebase.cloud.FirestoreClient.<init>(FirestoreClient.java:45)
    at com.google.firebase.cloud.FirestoreClient.<init>(FirestoreClient.java:29)
    at com.google.firebase.cloud.FirestoreClient$FirestoreClientService.<init>(FirestoreClient.java:95)
    at com.google.firebase.cloud.FirestoreClient.getInstance(FirestoreClient.java:85)
    at com.google.firebase.cloud.FirestoreClient.getFirestore(FirestoreClient.java:78)
    at com.google.firebase.cloud.FirestoreClient.getFirestore(FirestoreClient.java:64)
    at com.example.sampleapp.config.FirestoreConfig.db(FirestoreConfig.java:27)
    at com.example.sampleapp.config.$FirestoreConfig$Db0Definition.build(Unknown Source)
    at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1889)
    ... 103 common frames omitted

此时我对 Micronaut 和 GraalVM 都很陌生,所以我确定我忽略了一些简单的事情,但我没能找到很多关于这个特定错误的信息,以及我发现的事情确实找到并没有解决我的问题。

我正在使用 Micronaut 2.0.1 并使用 maven-shade-plugin 构建一个 fatJar,这就是我当时 运行 原生图像生成所反对的。

我的 Firestore 配置非常简单,如下所示:

@Factory
public class FirestoreConfig {

    private static final byte[] SVC_KEY = {123, 10, 32, .......};

    @Bean
    public Firestore db() throws Exception {
        InputStream serviceAccount = new ByteArrayInputStream(SVC_KEY);
        GoogleCredentials credentials = GoogleCredentials.fromStream(serviceAccount);
        FirebaseOptions options = new FirebaseOptions.Builder()
                .setCredentials(credentials)
                .build();
        FirebaseApp.initializeApp(options);
        return FirestoreClient.getFirestore();
    }

}

然后是我注入此配置的相关位:

@Slf4j
@Singleton
public class MailingListsApiServiceImpl extends MailingListsApiService {
    private final TokenGenerator tokenGenerator;
    private final Firestore db;
    private final ObjectMapper objectMapper;

    @Inject
    public MailingListsApiServiceImpl(
                                      TokenGenerator tokenGenerator,
                                      Firestore db,
                                      ObjectMapper objectMapper) {
        this.tokenGenerator = tokenGenerator;
        this.db = db;
        this.objectMapper = objectMapper;
    }

pom.xml

中的 Firebase 依赖项
<dependency>
  <groupId>com.google.firebase</groupId>
  <artifactId>firebase-admin</artifactId>
  <version>6.15.0</version>
</dependency>

如果我删除了 firebase-admin 依赖项并注释掉了 Firestore 的用法,那么我的请求确实得到了正确处理,所以它似乎肯定与那个和 gRPC 有关。

如有任何帮助,我们将不胜感激!

好像跟这个有关https://github.com/oracle/graal/issues/2694

他们已经解决了 netty 的类似问题,但可能需要为您的库提供额外的 PR https://github.com/netty/netty/pull/10428/commits/b18122834e3688cda6edc64af694cf6b06ac6b0d