Java17迁移后App Engine中Datastore查询报ApiProxy$CallNotFoundException
App Engine Java 17迁移:Datastore访问触发线程权限错误
问题描述
将App Engine上的Web应用从Java 8迁移至Java 17,应用使用Jakarta Servlet并打包为fat jar。Java 8环境下一切正常,但在Java 17中,仅执行简单的Datastore.get()方法时就会触发Google内部API错误,提示线程权限问题,且未自行创建任何线程。
错误栈
com.google.apphosting.api.ApiProxy$CallNotFoundException: Can't make API call datastore_v3.Get in a thread that is neither the original request thread nor a thread created by ThreadManager at com.google.apphosting.api.ApiProxy$CallNotFoundException.foreignThread(ApiProxy.java:855) at com.google.apphosting.api.ApiProxy$1.get(ApiProxy.java:183) at com.google.apphosting.api.ApiProxy$1.get(ApiProxy.java:180) at com.google.appengine.api.utils.FutureWrapper.get(FutureWrapper.java:107) at com.google.appengine.api.datastore.AsyncDatastoreServiceImpl$5.getFutureWithOptionalTimeout(AsyncDatastoreServiceImpl.java:361) at com.google.appengine.api.datastore.AsyncDatastoreServiceImpl$5.aggregate(AsyncDatastoreServiceImpl.java:330) at com.google.appengine.api.datastore.AsyncDatastoreServiceImpl$5.get(AsyncDatastoreServiceImpl.java:291) at com.google.appengine.api.datastore.AsyncDatastoreServiceImpl$5.get(AsyncDatastoreServiceImpl.java:280) at com.google.appengine.api.utils.FutureWrapper.get(FutureWrapper.java:107) at com.google.appengine.api.utils.FutureWrapper.get(FutureWrapper.java:107) at com.google.appengine.api.datastore.FutureHelper.getInternal(FutureHelper.java:83) at com.google.appengine.api.datastore.FutureHelper.quietGet(FutureHelper.java:70) at com.google.appengine.api.datastore.DatastoreServiceImpl.get(DatastoreServiceImpl.java:55)
依赖配置
<maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> <maven.clean.plugin.version>3.3.1</maven.clean.plugin.version> <maven.compiler.plugin.version>3.11.0</maven.compiler.plugin.version> <maven.dependency.plugin.version>3.6.0</maven.dependency.plugin.version> <maven.deploy.plugin.version>3.1.1</maven.deploy.plugin.version> <maven.enforcer.plugin.version>3.4.0</maven.enforcer.plugin.version> <maven.install.plugin.version>3.1.1</maven.install.plugin.version> <maven.shade.plugin.version>3.5.1</maven.shade.plugin.version> <maven.jar.plugin.version>3.3.0</maven.jar.plugin.version> <maven.war.plugin.version>3.4.0</maven.war.plugin.version> <maven.javadoc.plugin.version>3.5.0</maven.javadoc.plugin.version> <maven.resources.plugin.version>3.3.1</maven.resources.plugin.version> <maven.source.plugin.version>3.3.0</maven.source.plugin.version> <maven.surefire.plugin.version>3.1.2</maven.surefire.plugin.version> <exec.plugin.version>3.1.1</exec.plugin.version> <license.plugin.version>4.2</license.plugin.version> <jetty.version>11.0.15</jetty.version> <tomcat.version>10.1.18</tomcat.version> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-core</artifactId> <version>${tomcat.version}</version> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <version>${tomcat.version}</version> </dependency> <dependency> <groupId>com.google.cloud</groupId> <artifactId>google-cloud-storage</artifactId> <version>2.31.0</version> </dependency> <dependency> <groupId>com.google.appengine.tools</groupId> <artifactId>appengine-gcs-client</artifactId> <version>0.8.3</version> </dependency> <dependency> <groupId>com.google.cloud</groupId> <artifactId>google-cloud-datastore</artifactId> <version>2.17.3</version> </dependency>
排查方向与解决方案
1. 升级Datastore客户端版本
当前使用的google-cloud-datastore2.17.3版本可能存在Java 17兼容性问题,建议升级到2.x系列的最新稳定版。新版本通常修复了线程上下文传递、模块化适配等Java 17相关问题。
2. 规范线程创建方式
App Engine Java 17 runtime对线程上下文的管理比Java 8更严格,即使未手动创建线程,Tomcat内部线程池(如异步Servlet线程)可能未被App Engine的ThreadManager管理:
- 如果使用异步Servlet,必须通过
ThreadManager.createThreadForCurrentRequest()创建任务线程,而非直接使用Tomcat默认线程池。 - 检查依赖库在Java 17下的线程创建逻辑,避免第三方库创建的线程脱离App Engine上下文。
3. 解决Fat Jar依赖冲突
Fat Jar打包可能引入冲突的App Engine API依赖,导致类加载异常或上下文传递失败:
- 排除旧版
appengine-api-*间接依赖,确保仅使用google-cloud-datastore提供的客户端实现。 - 配置Maven Shade插件的
relocations规则,隔离冲突包(如com.google.appengine.api相关类),避免类版本冲突。
4. 验证Tomcat线程上下文传递
Tomcat 10.1.18兼容Jakarta Servlet 6.0,但需确认线程上下文是否正确传递给App Engine API:
- 临时禁用异步处理,改用同步请求测试,看是否还会触发错误。
- 检查Tomcat配置文件(
context.xml/server.xml)中的自定义线程池,确保线程初始化时注入App Engine上下文。
5. 调整Java 17模块化限制
Java 17的模块化系统可能限制App Engine API对线程上下文的反射访问,需在启动参数中添加:
--add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED
如果是fat jar打包,确保这些JVM参数被正确传递。
内容的提问来源于stack exchange,提问作者Kjell
相关产品推荐
相关产品推荐

