You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Tomcat中使用Firebase Java Admin SDK遇到API阻塞问题

在Apache Tomcat中使用Firebase Java Admin SDK出现API调用阻塞/超时问题

有人成功在Apache Tomcat中使用Firebase Java Admin SDK吗?我在Linux服务器上用Java 11(OpenJDK)、Tomcat 9.0.80和firebase-admin 9.2.0时遇到严重问题:FirebaseApp.initializeApp()看似初始化成功,但所有Firebase API调用均阻塞或超时。同一服务器上用相同Java版本、相同服务账号文件运行控制台程序时一切正常,可排除认证或网络问题。

环境信息

  • Java版本:OpenJDK 11
  • Tomcat版本:9.0.80
  • Firebase Admin SDK版本:9.2.0
  • 操作系统:Linux

初始化代码(放在ServletContextListener.contextInitialized()中)

org.apache.log4j.Logger.getLogger(CaasaAdminServletListener.class).info("[init]");
String serviceAccountKey = sce.getServletContext().getRealPath("/WEB-INF/firebase.json");
org.apache.log4j.Logger.getLogger(CaasaAdminServletListener.class).info("[init] serviceAccountKey= "+serviceAccountKey);
FileInputStream serviceAccount = new FileInputStream(serviceAccountKey);            
FirebaseOptions options = new FirebaseOptions.Builder()
              .setCredentials(GoogleCredentials.fromStream(serviceAccount))
              .setDatabaseUrl("https://mydatabase.firebaseio.com/")
              .build();
FirebaseApp.initializeApp(options);
org.apache.log4j.Logger.getLogger(CaasaAdminServletListener.class).info("[init] FirebaseApp.initializeApp OK");

阻塞的API调用代码(Servlet的processRequest方法中)

final FirebaseDatabase database = FirebaseDatabase.getInstance();
database.getReference().child(key).addListenerForSingleValueEvent(listener);

已尝试的排查操作

  • 同一服务器上的控制台程序可正常读写Firebase数据库,同步异步API均可用;
  • 尝试过在静态代码块、Servlet.init方法或API调用前初始化Firebase,均无效;
  • 对比控制台程序(正常)与Tomcat Web应用(异常)的Firebase调试日志,发现Web应用中缺少io.netty内部消息系统的初始化日志。

日志对比

两者共有的初始日志片段

12 10 2023 10:27:41 DEBUG firebase-database-worker io.netty.util.internal.logging.InternalLoggerFactory - Using Log4J as the default logging framework
12 10 2023 10:27:41 DEBUG firebase-database-worker io.netty.util.internal.InternalThreadLocalMap - -Dio.netty.threadLocalMap.stringBuilder.initialSize: 1024
12 10 2023 10:27:41 DEBUG firebase-database-worker io.netty.util.internal.InternalThreadLocalMap - -Dio.netty.threadLocalMap.stringBuilder.maxSize: 4096
12 10 2023 10:27:41 DEBUG firebase-database-worker io.netty.util.internal.PlatformDependent0 - -Dio.netty.noUnsafe: false
12 10 2023 10:27:41 DEBUG firebase-database-worker io.netty.util.internal.PlatformDependent0 - Java version: 11
12 10 2023 10:27:41 DEBUG firebase-database-worker io.netty.util.internal.PlatformDependent0 - sun.misc.Unsafe.theUnsafe: available
12 10 2023 10:27:41 DEBUG firebase-database-worker io.netty.util.internal.PlatformDependent0 - sun.misc.Unsafe.copyMemory: available
12 10 2023 10:27:41 DEBUG firebase-database-worker io.netty.util.internal.PlatformDependent0 - sun.misc.Unsafe.storeFence: available
12 10 2023 10:27:41 DEBUG firebase-database-worker io.netty.util.internal.PlatformDependent0 - java.nio.Buffer.address: available
12 10 2023 10:27:41 DEBUG firebase-database-worker io.netty.util.internal.PlatformDependent0 - direct buffer constructor: unavailable: Reflective setAccessible(true) disabled
12 10 2023 10:27:41 DEBUG firebase-database-worker io.netty.util.internal.PlatformDependent0 - java.nio.Bits.unaligned: available, true
12 10 2023 10:27:41 DEBUG firebase-database-worker io.netty.util.internal.PlatformDependent0 - jdk.internal.misc.Unsafe.allocateUninitializedArray(int): unavailable: class io.netty.util.internal.PlatformDependent0$7 cannot access class jdk.internal.misc.Unsafe (in module java.base) because module java.base does not export jdk.internal.misc to unnamed module @6c382782
12 10 2023 10:27:41 DEBUG firebase-database-worker io.netty.util.internal.PlatformDependent0 - java.nio.DirectByteBuffer.<init>(long, {int,long}): unavailable
12 10 2023 10:27:41 DEBUG firebase-database-worker io.netty.util.internal.PlatformDependent - sun.misc.Unsafe: available
12 10 2023 10:27:41 DEBUG firebase-database-worker io.netty.util.internal.PlatformDependent - maxDirectMemory: 7677673472 bytes (maybe)
12 10 2023 10:27:41 DEBUG firebase-database-worker io.netty.util.internal.PlatformDependent - -Dio.netty.tmpdir: /tmp (java.io.tmpdir)
12 10 2023 10:27:41 DEBUG firebase-database-worker io.netty.util.internal.PlatformDependent - -Dio.netty.bitMode: 64 (sun.arch.data.model)
12 10 2023 10:27:41 DEBUG firebase-database-worker io.netty.util.internal.PlatformDependent - -Dio.netty.maxDirectMemory: -1 bytes
12 10 2023 10:27:41 DEBUG firebase-database-worker io.netty.util.internal.PlatformDependent - -Dio.netty.uninitializedArrayAllocationThreshold: -1
12 10 2023 10:27:41 DEBUG firebase-database-worker io.netty.util.internal.CleanerJava9 - java.nio.ByteBuffer.cleaner(): available
12 10 2023 10:27:41 DEBUG firebase-database-worker io.netty.util.internal.PlatformDependent - -Dio.netty.noPreferDirect: false

仅控制台程序存在的日志片段

12 10 2023 10:27:41 DEBUG firebase-database-worker io.netty.channel.MultithreadEventLoopGroup - -Dio.netty.eventLoopThreads: 16
12 10 2023 10:27:41 DEBUG firebase-database-worker io.netty.util.concurrent.GlobalEventExecutor - -Dio.netty.globalEventExecutor.quietPeriodSeconds: 1
12 10 2023 10:27:41 DEBUG firebase-database-worker io.netty.channel.nio.NioEventLoop - -Dio.netty.noKeySetOptimization: false
12 10 2023 10:27:41 DEBUG firebase-database-worker io.netty.channel.nio.NioEventLoop - -Dio.netty.selectorAutoRebuildThreshold: 512
12 10 2023 10:27:41 DEBUG firebase-database-worker io.netty.util.internal.PlatformDependent - org.jctools-core.MpscChunkedArrayQueue: available
12 10 2023 10:27:41 DEBUG firebase-database-worker io.netty.handler.ssl.OpenSsl - netty-tcnative not in the classpath; OpenSslEngine will be unavailable.
12 10 2023 10:27:41 DEBUG firebase-database-worker io.netty.handler.ssl.JdkSslContext - Default protocols (JDK): [TLSv1.3, TLSv1.2]
12 10 2023 10:27:41 DEBUG firebase-database-worker io.netty.handler.ssl.JdkSslContext - Default cipher suites (JDK): [TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384]
12 10 2023 10:27:41 DEBUG firebase-database-worker io.netty.channel.DefaultChannelId - -Dio.netty.processId: 17423 (auto-detected)
12 10 2023 10:27:41 DEBUG firebase-database-worker io.netty.util.NetUtil - -Djava.net.preferIPv4Stack: false
.... 

可能的解决方案

根据日志缺失和Tomcat类加载特性,问题大概率和Netty的类加载冲突或线程初始化被Tomcat上下文限制有关,可尝试以下操作:

  1. 调整Tomcat的类加载属性
    在Tomcat的conf/context.xml中添加antiResourceLocking="false"和antiJARLocking="false",避免类加载时的资源锁定导致Netty初始化失败:

    <Context antiResourceLocking="false" antiJARLocking="false">
        <!-- 其他配置 -->
    </Context>
    
  2. 强制指定Netty的线程模型
    在Firebase初始化前,手动设置Netty的系统属性,确保EventLoop线程正常初始化:

    System.setProperty("io.netty.eventLoopThreads", "16");
    System.setProperty("io.netty.selectorAutoRebuildThreshold", "512");
    // 然后再执行Firebase初始化代码
    FirebaseOptions options = new FirebaseOptions.Builder()
          .setCredentials(GoogleCredentials.fromStream(serviceAccount))
          .setDatabaseUrl("https://mydatabase.firebaseio.com/")
          .build();
    FirebaseApp.initializeApp(options);
    
  3. 升级Firebase Admin SDK版本
    9.2.0版本相对较旧,尝试升级到较新的稳定版本(比如最新的9.x或10.x版本),新版本可能修复了Web容器下的类加载和Netty初始化问题。

  4. 检查Tomcat的安全管理器配置
    如果Tomcat启用了安全管理器,可能限制了Netty反射调用相关的权限,需要在conf/catalina.policy中添加对应的权限:

    grant codeBase "file:${catalina.base}/webapps/你的应用名称/-" {
        permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
        permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
    };
    

内容的提问来源于stack exchange,提问作者Andrea Murru

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 07:32:03