Spring Boot迁移至Cloud Spanner遇DirectedReadOptions类缺失错误
Spring Boot迁移Cloud Spanner时的类缺失错误解决
问题场景
将基于Spring 3、Java 17,使用最新Hibernate和JPA的Spring Boot应用从Cloud SQL(PostgreSQL)迁移到Cloud Spanner,采用Google SQL方言交互时,启动报错。
错误日志
Caused by: java.lang.ExceptionInInitializerError: null at com.google.cloud.spanner.connection.ConnectionImpl.<clinit>(ConnectionImpl.java:135) at com.google.cloud.spanner.connection.ConnectionOptions.getConnection(ConnectionOptions.java:1073) at com.google.cloud.spanner.jdbc.AbstractJdbcConnection.<init>(AbstractJdbcConnection.java:65) at com.google.cloud.spanner.jdbc.JdbcConnection.<init>(JdbcConnection.java:56) at com.google.cloud.spanner.jdbc.JdbcDriver.connect(JdbcDriver.java:196) at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:121) at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:359) at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:201) at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:470) at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:561) at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:100) at com.zaxxer.hikari.HikariDataSource.<init>(HikariDataSource.java:81) at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:62) at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:502) at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:486) at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:208) ... 37 common frames omitted Caused by: com.google.cloud.spanner.SpannerException: INTERNAL: Could not instantiate statement parser for dialect GOOGLE_STANDARD_SQL at com.google.cloud.spanner.SpannerExceptionFactory.newSpannerExceptionPreformatted(SpannerExceptionFactory.java:319) at com.google.cloud.spanner.SpannerExceptionFactory.newSpannerExceptionPreformatted(SpannerExceptionFactory.java:325) at com.google.cloud.spanner.SpannerExceptionFactory.newSpannerException(SpannerExceptionFactory.java:62) at com.google.cloud.spanner.connection.AbstractStatementParser.getInstance(AbstractStatementParser.java:93) at com.google.cloud.spanner.connection.AbstractStatementParser.<clinit>(AbstractStatementParser.java:145) ... 55 common frames omitted Caused by: java.lang.reflect.InvocationTargetException: null at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:74) at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:502) at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:486) at com.google.cloud.spanner.connection.AbstractStatementParser.getInstance(AbstractStatementParser.java:91) ... 56 common frames omitted Caused by: com.google.cloud.spanner.connection.ClientSideStatementImpl$CompileException: Could not compile statement SHOW VARIABLE AUTOCOMMIT at com.google.cloud.spanner.connection.ClientSideStatementImpl.compile(ClientSideStatementImpl.java:159) at com.google.cloud.spanner.connection.ClientSideStatements.getCompiledStatements(ClientSideStatements.java:76) at com.google.cloud.spanner.connection.SpannerStatementParser.<init>(SpannerStatementParser.java:41) at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:62) ... 59 common frames omitted Caused by: java.lang.reflect.InvocationTargetException: null at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:74) at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:502) at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:486) at com.google.cloud.spanner.connection.ClientSideStatementImpl.compile(ClientSideStatementImpl.java:156) ... 62 common frames omitted Caused by: java.lang.NoClassDefFoundError: com/google/spanner/v1/DirectedReadOptions at java.base/java.lang.Class.getDeclaredMethods0(Native Method) at java.base/java.lang.Class.privateGetDeclaredMethods(Class.java:3578) at java.base/java.lang.Class.getDeclaredMethod(Class.java:2846) at com.google.cloud.spanner.connection.ClientSideStatementNoParamExecutor.<init>(ClientSideStatementNoParamExecutor.java:39) at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:62) ... 65 common frames omitted Caused by: java.lang.ClassNotFoundException: com.google.spanner.v1.DirectedReadOptions at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641) at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:526) ... 70 common frames omitted
当前依赖配置
<dependency> <groupId>com.google.cloud</groupId> <artifactId>google-cloud-spanner-hibernate-dialect</artifactId> <version>3.3.0</version> </dependency> <dependency> <groupId>com.google.cloud</groupId> <artifactId>google-cloud-spanner</artifactId> <version>6.80.1</version> </dependency> <dependency> <groupId>com.google.cloud</groupId> <artifactId>spring-cloud-gcp-data-spanner</artifactId> <version>5.8.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-rest</artifactId> <version>3.3.5</version> </dependency> <dependency> <groupId>com.google.cloud</groupId> <artifactId>google-cloud-spanner-jdbc</artifactId> <version>2.8.0</version> </dependency>
解决方法
1. 统一Spanner相关依赖版本
核心问题是google-cloud-spanner(6.80.1)和google-cloud-spanner-jdbc(2.8.0)版本不兼容,导致gRPC proto类缺失。建议使用Spring Cloud GCP的BOM来统一管理所有Google Cloud依赖版本,避免手动指定版本冲突:
在pom.xml中添加依赖管理:
<dependencyManagement> <dependencies> <dependency> <groupId>com.google.cloud</groupId> <artifactId>spring-cloud-gcp-dependencies</artifactId> <version>5.8.0</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
然后调整依赖,移除手动指定的版本号:
<dependency> <groupId>com.google.cloud</groupId> <artifactId>google-cloud-spanner-hibernate-dialect</artifactId> </dependency> <dependency> <groupId>com.google.cloud</groupId> <artifactId>google-cloud-spanner</artifactId> </dependency> <dependency> <groupId>com.google.cloud</groupId> <artifactId>spring-cloud-gcp-data-spanner</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-rest</artifactId> </dependency> <dependency> <groupId>com.google.cloud</groupId> <artifactId>google-cloud-spanner-jdbc</artifactId> </dependency>
2. 清理依赖缓存并重新构建
执行Maven命令清理并重新下载依赖:
mvn clean install -U
3. 检查冗余依赖
如果你的应用仅使用Hibernate/JPA访问Spanner,可考虑移除spring-cloud-gcp-data-spanner依赖,避免两种数据访问框架冲突;如果同时需要Spring Data Spanner的Repository支持,则保留该依赖。
内容的提问来源于stack exchange,提问作者Suga Raj
相关产品推荐
相关产品推荐

