与 NameResolverProvider 相关的 gRPC 异常

gRPC exception related with NameResolverProvider

我有一个用 Java 编写的 gRPC 服务器,它试图通过具有项目所有者角色的服务帐户访问 Firestore 和其他服务。服务器 运行 成功了很多次,但是当我再次尝试 运行 时,发生了这种情况:

Exception in thread "main" java.util.ServiceConfigurationError: io.grpc.NameResolverProvider: Provider io.grpc.grpclb.SecretGrpclbNameResolverProvider$Provider could not be instantiated
    at java.util.ServiceLoader.fail(ServiceLoader.java:232)
    at java.util.ServiceLoader.access0(ServiceLoader.java:185)
    at java.util.ServiceLoader$LazyIterator.nextService(ServiceLoader.java:384)
    at java.util.ServiceLoader$LazyIterator.next(ServiceLoader.java:404)
    at java.util.ServiceLoader.next(ServiceLoader.java:480)
    at io.grpc.ServiceProviders.loadAll(ServiceProviders.java:67)
    at io.grpc.NameResolverRegistry.getDefaultRegistry(NameResolverRegistry.java:101)
    at io.grpc.internal.AbstractManagedChannelImplBuilder.<init>(AbstractManagedChannelImplBuilder.java:107)
    at io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder.<init>(NettyChannelBuilder.java:136)
    at io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder.<init>(NettyChannelBuilder.java:131)
    at io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder.forAddress(NettyChannelBuilder.java:117)
    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:270)
    at com.google.api.gax.grpc.InstantiatingGrpcChannelProvider.access00(InstantiatingGrpcChannelProvider.java:71)
    at com.google.api.gax.grpc.InstantiatingGrpcChannelProvider.createSingleChannel(InstantiatingGrpcChannelProvider.java:202)
    at com.google.api.gax.grpc.ChannelPool.create(ChannelPool.java:72)
    at com.google.api.gax.grpc.InstantiatingGrpcChannelProvider.createChannel(InstantiatingGrpcChannelProvider.java:209)
    at com.google.api.gax.grpc.InstantiatingGrpcChannelProvider.getTransportChannel(InstantiatingGrpcChannelProvider.java:192)
    at com.google.api.gax.rpc.ClientContext.create(ClientContext.java:155)
    at com.google.api.gax.rpc.ClientContext.create(ClientContext.java:122)
    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 services.FirestoreServiceActions.<init>(FirestoreServiceActions.java:25)
    at CNTextServer.main(CNTextServer.java:47)
Caused by: java.lang.VerifyError: Cannot inherit from final class
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:756)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:468)
    at java.net.URLClassLoader.access0(URLClassLoader.java:74)
    at java.net.URLClassLoader.run(URLClassLoader.java:369)
    at java.net.URLClassLoader.run(URLClassLoader.java:363)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:355)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
    at java.lang.Class.getDeclaredConstructors0(Native Method)
    at java.lang.Class.privateGetDeclaredConstructors(Class.java:2671)
    at java.lang.Class.getConstructor0(Class.java:3075)
    at java.lang.Class.newInstance(Class.java:412)
    at java.util.ServiceLoader$LazyIterator.nextService(ServiceLoader.java:380)
    ... 30 more

为了简化事情并解决 IntelliJ Idea 上可能发生的一些主要问题, 我创建了一个更简单的 (Maven) 项目,它只有一些启动服务器的代码,并且运行良好,服务器 运行 完美无缺。 虽然,当我添加初始化 Firestore 服务的行时,会抛出相同的异常。

我有一个环境变量 (GOOGLE_APPLICATION_CREDENTIALS) 指向具有项目所有者角色的服务帐户的密钥,就像我之前提到的那样。我也尝试了 FileInputStream 替代方案,指向密钥,但没有成功。

我的更简单(Maven)项目的代码是:


private static final int SERVICE_PORT = 8000;
private Firestore firestoreService

public static void main(String[] args) {
        try {
            System.out.println("--> SETTING UP THE SERVER...");

            GoogleCredentials credentials = GoogleCredentials.fromStream(new FileInputStream(SERVICE_ACCOUNT_KEY_PATH));

            this.firestoreService = FirestoreOptions.newBuilder().setCredentials(credentials).build().getService();

            Server service = ServerBuilder
                    .forPort(SERVICE_PORT)
                    .addService(new CNTextServer())
                    .build();

            service.start();

            System.out.println("--- SERVER STARTED. LISTENING ON PORT " + SERVICE_PORT);
            System.out.println("--> PRESS 'ENTER' TO STOP THE SERVER");
            Scanner scanner = new Scanner(System.in);
            scanner.nextLine();

            System.out.println("<-- SERVER SHUTTING DOWN...");
            service.shutdown();
        } catch (Exception ex) {
            System.out.println("### EXCEPTION ON SERVER.MAIN() ###\n" + ex.getMessage());
        }
    }

Maven pom.xml 文件的依赖是:

 <dependencies>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-netty-shaded</artifactId>
            <version>1.28.0</version>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-protobuf</artifactId>
            <version>1.28.0</version>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-stub</artifactId>
            <version>1.28.0</version>
        </dependency>
        <dependency>
            <groupId>com.google.cloud</groupId>
            <artifactId>google-cloud-firestore</artifactId>
            <version>1.34.0</version>
        </dependency>
        <dependency>
            <groupId>com.google.cloud</groupId>
            <artifactId>google-cloud-storage</artifactId>
            <version>1.108.0</version>
        </dependency>
        <dependency>
            <groupId>com.google.cloud</groupId>
            <artifactId>google-cloud-pubsub</artifactId>
            <version>1.106.0</version>
        </dependency>
        <dependency>
            <groupId>com.google.cloud</groupId>
            <artifactId>google-cloud-compute</artifactId>
            <version>0.118.0-alpha</version>
        </dependency>
        <dependency>
            <groupId>com.google.cloud</groupId>
            <artifactId>google-cloud-vision</artifactId>
            <version>1.99.3</version>
        </dependency>
        <dependency>
            <groupId>com.google.cloud</groupId>
            <artifactId>google-cloud-translate</artifactId>
            <version>1.94.5</version>
        </dependency>
        <dependency>
            <groupId>leic.cn.li62d-g04</groupId>
            <artifactId>CNTextContract</artifactId>
            <version>1.0</version>
            <scope>system</scope>
            <systemPath>${basedir}/../CNTextContract/target/CNTextContract-1.0-SNAPSHOT.jar</systemPath>
        </dependency>
    </dependencies>

运行 mvn dependency:tree 我们看到:

[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ examples ---
[INFO] com.example:examples:jar:1.0.0
[INFO] +- io.grpc:grpc-netty-shaded:jar:1.28.0:compile
[INFO] |  \- io.grpc:grpc-core:jar:1.28.0:compile (version selected from constraint [1.28.0,1.28.0])
[INFO] +- io.grpc:grpc-protobuf:jar:1.28.0:compile
[INFO] |  +- io.grpc:grpc-api:jar:1.28.0:compile
[INFO] |  +- com.google.protobuf:protobuf-java:jar:3.11.0:compile
[INFO] |  +- com.google.guava:guava:jar:28.1-android:compile
[INFO] |  +- com.google.api.grpc:proto-google-common-protos:jar:1.17.0:compile
[INFO] |  \- io.grpc:grpc-protobuf-lite:jar:1.28.0:compile
[INFO] +- io.grpc:grpc-stub:jar:1.28.0:compile
[INFO] +- com.google.cloud:google-cloud-firestore:jar:1.34.0:compile
[INFO] |  +- com.google.cloud:google-cloud-core-grpc:jar:1.93.5:compile
...
[INFO] |  +- io.grpc:grpc-context:jar:1.29.0:compile
[INFO] |  +- com.google.api:gax:jar:1.56.0:compile
[INFO] |  +- com.google.auth:google-auth-library-oauth2-http:jar:0.20.0:compile
[INFO] |  +- com.google.errorprone:error_prone_annotations:jar:2.3.4:compile
[INFO] |  +- org.codehaus.mojo:animal-sniffer-annotations:jar:1.18:compile
[INFO] |  +- com.google.api:gax-grpc:jar:1.56.0:compile
[INFO] |  +- io.grpc:grpc-auth:jar:1.29.0:compile
[INFO] |  +- io.grpc:grpc-alts:jar:1.29.0:compile
[INFO] |  +- io.grpc:grpc-grpclb:jar:1.29.0:compile

问题是grpc-core太旧了。您可以看到 io.grpc:grpc-core:jar:1.28.0io.grpc:grpc-grpclb:jar:1.29.0:compile。 grpclb 依赖于 grpc-core 1.29.0。在 1.29.0 中添加了 GrpclbNameResolver,它从 grpc-core 扩展了 DnsNameResolver。但在 1.28.0 中,DnsNameResolver 是 final。降级很可能导致破损。

要解决版本问题(有几个),将 io.grpc 依赖项移到最后,将它们的版本升级到 1.29.0。

      <dependencies>
        <dependency>
            <groupId>com.google.cloud</groupId>
            <artifactId>google-cloud-firestore</artifactId>
            <version>1.34.0</version>
        </dependency>
        <dependency>
            <groupId>com.google.cloud</groupId>
            <artifactId>google-cloud-storage</artifactId>
            <version>1.108.0</version>
        </dependency>
        <dependency>
            <groupId>com.google.cloud</groupId>
            <artifactId>google-cloud-pubsub</artifactId>
            <version>1.106.0</version>
        </dependency>
        <dependency>
            <groupId>com.google.cloud</groupId>
            <artifactId>google-cloud-compute</artifactId>
            <version>0.118.0-alpha</version>
        </dependency>
        <dependency>
            <groupId>com.google.cloud</groupId>
            <artifactId>google-cloud-vision</artifactId>
            <version>1.99.3</version>
        </dependency>
        <dependency>
            <groupId>com.google.cloud</groupId>
            <artifactId>google-cloud-translate</artifactId>
            <version>1.94.5</version>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-netty-shaded</artifactId>
            <version>1.29.0</version>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-protobuf</artifactId>
            <version>1.29.0</version>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-stub</artifactId>
            <version>1.29.0</version>
        </dependency>
    </dependencies>

Maven 的传递依赖解析很差,并且在没有任何警告的情况下愉快地降级包。最好使用 maven-enforcer 的 requireUpperBoundDeps 来检测这样的问题:

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-enforcer-plugin</artifactId>
        <version>1.4.1</version>
        <executions>
          <execution>
            <id>enforce</id>
            <goals>
              <goal>enforce</goal>
            </goals>
            <configuration>
              <rules>
                <requireUpperBoundDeps/>
              </rules>
            </configuration>
          </execution>
        </executions>
      </plugin>

由于依赖关系被破坏,它会注意到降级:

[WARNING] Rule 0: org.apache.maven.plugins.enforcer.RequireUpperBoundDeps failed with message:
Failed while enforcing RequireUpperBoundDeps. The error(s) are [
Require upper bound dependencies error for io.grpc:grpc-netty-shaded:1.28.0 paths to dependency are:
+-com.example:examples:1.0.0
  +-io.grpc:grpc-netty-shaded:1.28.0
and
+-com.example:examples:1.0.0
  +-com.google.cloud:google-cloud-firestore:1.34.0
    +-io.grpc:grpc-netty-shaded:1.29.0
, 
Require upper bound dependencies error for io.grpc:grpc-protobuf:1.28.0 paths to dependency are:
+-com.example:examples:1.0.0
  +-io.grpc:grpc-protobuf:1.28.0
and
+-com.example:examples:1.0.0
  +-com.google.cloud:google-cloud-firestore:1.34.0
    +-io.grpc:grpc-protobuf:1.29.0
and
+-com.example:examples:1.0.0
  +-com.google.cloud:google-cloud-pubsub:1.106.0
    +-io.grpc:grpc-protobuf:1.29.0
...