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

Spring Boot读取resources下PEM文件在服务器/Docker中报错的解决方案

Spring Boot读取resources下PEM文件部署后空指针问题解决

问题现象

本地启动Spring Boot应用时,读取src/main/resources目录下的marchent_private.pem文件正常,但将jar包部署到VPS服务器或通过Docker运行时,抛出如下异常:

java.lang.NullPointerException: Cannot invoke "String.getBytes(java.nio.charset.Charset)" because "src" is null

用户使用的读取代码如下:

public PrivateKey getPrivate() throws Exception {
    ClassPathResource resource = new ClassPathResource("marchent_private.pem");
    InputStream inputStream = resource.getInputStream();
    BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
    String content = reader.readLine();
    System.out.println(content);

    content = content.replaceAll("\\s", "");

    byte[] keyBytes = Base64.getDecoder().decode(content);
    PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
    KeyFactory kf = KeyFactory.getInstance("RSA");
    return kf.generatePrivate(spec);
}

问题原因

  1. PEM文件读取不完整:PEM格式私钥包含多行内容(含头尾标记行),代码仅用readLine()读取第一行,部署环境中可能因编码、换行格式差异导致第一行读取为空,触发空指针。
  2. 流未正确关闭:代码未处理流的关闭操作,可能引发资源泄漏或读取异常。
  3. 资源打包问题:jar包构建时可能未将marchent_private.pem正确打包进去,导致运行时无法找到文件。

解决方案

1. 修正PEM文件读取逻辑

改为读取所有行,过滤头尾标记并拼接有效内容,同时使用try-with-resources自动关闭流:

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import org.springframework.core.io.ClassPathResource;

public PrivateKey getPrivate() throws Exception {
    ClassPathResource resource = new ClassPathResource("marchent_private.pem");
    
    // try-with-resources自动关闭流,避免资源泄漏
    try (InputStream inputStream = resource.getInputStream();
         BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
        
        StringBuilder keyContent = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            // 跳过私钥的头尾标记行
            if (!line.startsWith("-----BEGIN PRIVATE KEY-----") && !line.startsWith("-----END PRIVATE KEY-----")) {
                keyContent.append(line.trim());
            }
        }
        
        String encodedKey = keyContent.toString();
        if (encodedKey.isEmpty()) {
            throw new IllegalArgumentException("私钥文件内容无效或为空");
        }

        byte[] keyBytes = Base64.getDecoder().decode(encodedKey);
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePrivate(spec);
    }
}

2. 验证资源文件是否正确打包

  • 执行命令检查jar包内是否包含目标文件:
    jar tf your-app.jar | grep marchent_private.pem
    
    若输出为空,说明文件未被打包,需检查构建工具配置:
    • Maven项目确保pom.xml中没有排除src/main/resources的配置,默认Maven会自动打包该目录下的文件。
    • Gradle项目确保build.gradle中包含sourceSets.main.resources.srcDirs = ['src/main/resources']配置。

3. Docker部署检查

  • 确保Dockerfile正确复制了包含资源文件的jar包:
    FROM openjdk:17-jdk-slim
    WORKDIR /app
    COPY target/your-app.jar ./app.jar
    CMD ["java", "-jar", "app.jar"]
    
  • 构建镜像前,先执行mvn clean package(Maven)或gradle build(Gradle)生成最新的jar包,避免使用旧包导致资源缺失。

内容的提问来源于stack exchange,提问作者Rumaion Tomal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 12:44:57