首页 > 解决方案 > Google Cloud Function java.lang.NoClassDefFoundError,同时遵循示例代码

问题描述

我尝试使用存储触发器测试 gcloud 功能。gcloud 函数应该调用一个公共的 gcloud 服务,但需要身份验证。我可以毫无问题地在本地执行该功能。但是在 gcloud 上,我可以在函数日志中找到 NoClassDefFoundError。

无法执行函数。HelloGcs java.lang.NoClassDefFoundError: io/opencensus/trace/propagation/TextFormat$Setter at com.google.api.client.http.HttpRequest.(HttpRequest.java:203) at com.google.api。 client.http.HttpTransport.buildRequest(HttpTransport.java:115) 在 com.google.api.client.http.HttpRequestFactory.buildRequest(HttpRequestFactory.java:86) 在 com.google.api.client.http.HttpRequestFactory.buildGetRequest( HttpRequestFactory.java:117) 在 com.google.auth.oauth2.ComputeEngineCredentials.runningOnComputeEngine(ComputeEngineCredentials.java:285) 在 com.google.auth.oauth2.DefaultCredentialsProvider.tryGetComputeCredentials(DefaultCredentialsProvider.java:314) 在 com.google.auth .oauth2.DefaultCredentialsProvider.getDefaultCredentialsUnsynchronized(DefaultCredentialsProvider.java:223) 在 com.google.auth.oauth2.DefaultCredentialsProvider。getDefaultCredentials(DefaultCredentialsProvider.java:126) 在 com.google.auth.oauth2.GoogleCredentials.getApplicationDefault(GoogleCredentials.java:124) 在 com.google.auth.oauth2.GoogleCredentials.getApplicationDefault(GoogleCredentials.java:96) 在 functions.HelloGcs .makeGetRequest(HelloGcs.java:44) 在functions.HelloGcs.accept(HelloGcs.java:37) 在functions.HelloGcs.accept(HelloGcs.java:21) 在com.google.cloud.functions.invoker.BackgroundFunctionExecutor$TypedFunctionExecutor。 serviceLegacyEvent(BackgroundFunctionExecutor.java:285) at com.google.cloud.functions.invoker.BackgroundFunctionExecutor.lambda$serviceLegacyEvent$8(BackgroundFunctionExecutor.java:375) at com.google.cloud.functions.invoker.BackgroundFunctionExecutor.runWithContextClassLoader(BackgroundFunctionExecutor.java :382) 在 com.google.cloud.functions.invoker。BackgroundFunctionExecutor.serviceLegacyEvent(BackgroundFunctionExecutor.java:375) at com.google.cloud.functions.invoker.BackgroundFunctionExecutor.service(BackgroundFunctionExecutor.java:330) at javax.servlet.http.HttpServlet.service(HttpServlet.java:790) at org .eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:755) 在 org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:547) 在 org.eclipse.jetty.server.handler.ScopedHandler.nextHandle (ScopedHandler.java:233) 在 org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1297) 在 org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188) 在org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:485) 在 org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186) 在 org.eclipse.jetty.server。handler.ContextHandler.doScope(ContextHandler.java:1212) 在 org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) 在 org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper. java:127) 在 com.google.cloud.functions.invoker.runner.Invoker$NotFoundHandler.handle(Invoker.java:392) 在 org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)在 org.eclipse.jetty.server.Server.handle(Server.java:500) 在 org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:383) 在 org.eclipse.jetty.server。 org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:375) 的 HttpChannel.dispatch(HttpChannel.java:547) org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:270) 的 org .eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311) 在 org。eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103) 在 org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:117) 在 org.eclipse.jetty.util.thread.strategy.EatWhatYouKill .runTask(EatWhatYouKill.java:336) 在 org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:313) 在 org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill .java:171) 在 org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:388) 的 org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:129) ) 在 org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:806) 在 org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:938) 在 java.base/ java.lang.Thread.run(Thread.java:829) 引起:java.lang。ClassNotFoundException:io.opencensus.trace.propagation.TextFormat$Setter at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:471) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:589 ) 在 java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522) ... 47 更多

设置:

如您所见,我使用此处的云触发器 java 示例代码: https ://cloud.google.com/functions/docs/calling/storage?hl=de#functions-calling-storage-java

我从这里通过静态函数扩展了代码: https ://cloud.google.com/run/docs/authenticating/service-to-service#acquire-token

最终演示类的代码:

package functions;

import com.google.cloud.functions.BackgroundFunction;
import com.google.cloud.functions.Context;
import functions.eventpojos.GcsEvent;

import java.io.IOException;
import java.util.logging.Logger;

import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpResponse;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.auth.oauth2.IdTokenCredentials;
import com.google.auth.oauth2.IdTokenProvider;


public class HelloGcs implements BackgroundFunction<GcsEvent> {
    private static final Logger logger = Logger.getLogger(HelloGcs.class.getName());

    private static final String PATH = "https://demo/api/smoke";

    @Override
    public void accept(GcsEvent event, Context context) {
        logger.info("Event: " + context.eventId());
        logger.info("Event Type: " + context.eventType());
        logger.info("Bucket: " + event.getBucket());
        logger.info("File: " + event.getName());
        logger.info("Metageneration: " + event.getMetageneration());
        logger.info("Created: " + event.getTimeCreated());
        logger.info("Updated: " + event.getUpdated());
        logger.info("Call: " + PATH);
        try {
            makeGetRequest(PATH);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

      public static HttpResponse makeGetRequest(String serviceUrl) throws IOException {
        GoogleCredentials credentials = GoogleCredentials.getApplicationDefault();
        if (!(credentials instanceof IdTokenProvider)) {
          throw new IllegalArgumentException("Credentials are not an instance of IdTokenProvider.");
        }
        IdTokenCredentials tokenCredential =
            IdTokenCredentials.newBuilder()
                .setIdTokenProvider((IdTokenProvider) credentials)
                .setTargetAudience(serviceUrl)
                .build();

        GenericUrl genericUrl = new GenericUrl(serviceUrl);
        HttpCredentialsAdapter adapter = new HttpCredentialsAdapter(tokenCredential);
        HttpTransport transport = new NetHttpTransport();
        HttpRequest request = transport.createRequestFactory(adapter).buildGetRequest(genericUrl);
        return request.execute();
      }
}

示例代码已上传

gcloud 函数部署 java-gcs-function
--entry-point functions.HelloGcs
--runtime java11
--memory 512MB
--trigger-resource YOUR_TRIGGER_BUCKET_NAME
--trigger-event google.storage.object.finalize

该功能的所有者是一个额外的服务帐户(如此处所述https://cloud.google.com/run/docs/authenticating/service-to-service章节“设置服务帐户”)

在此先感谢您的帮助,我们将不胜感激。

标签: javagoogle-cloud-platformgoogle-cloud-functions

解决方案


例外情况是您所依赖的外部库在程序的类路径中不可用。

解决这个问题的最简单方法是将您的代码作为胖 jar提交,以便所有依赖项在运行时都可用。


推荐阅读