无法在 docker 容器内以非阻塞方式读取类路径资源文件

Unable to read classpath resource file in non-blocking way inside docker container

我正在尝试从 src/main/resources 目录加载 JSON 文件 sample.json

我必须将 json 映射到 Java 对象。我的应用程序是反应式的,我正在使用 Spring webflux.

我跟着Simon's Blog想出了这个:

    SimpleModule module = new SimpleModule();
    module.addDeserializer(OffsetDateTime.class, new JsonDeserializer<>() {
      @Override
      public OffsetDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        return OffsetDateTime.parse(p.getValueAsString());
      }
    });

    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.registerModule(module);


    return Flux.using(() -> Files.lines(Paths.get(ClassLoader.getSystemResource("sample.json").toURI())),
        Flux::fromStream,
        BaseStream::close
    )
        .collectList()
        .map(lines -> String.join("\n", lines))
        .map(jsonContent -> {
          try {
            return objectMapper.readValue(jsonContent, MyPojo.class);
          } catch (JsonProcessingException e) {
            e.printStackTrace();
            return null;
          }
        })
        .map(MyPojo::getValues());

这在本地工作正常,但在 运行 在 docker 容器内时失败。 (我正在使用 gradle 构建来构建 jar 文件,然后从中构建 docker 图像)

部分错误堆栈跟踪:

java.nio.file.FileSystemNotFoundException: null at jdk.zipfs/jdk.nio.zipfs.ZipFileSystemProvider.getFileSystem(ZipFileSystemProvider.java:169) ~[jdk.zipfs:na] Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:

当 运行 docker 图像时,您正试图从 Jar 中访问文件。而且似乎将资源 URI 直接传递给 Paths.get 是行不通的。

您可以参考以下有关相同的Whosebug讨论:

  1. 这个answer
  2. 的回答
  3. this question
  4. 的回答

我认为你应该看一下 Spring 的 this class,它将字节流解码为 JSON 并使用 Jackson 2.9 转换为对象,利用 non-blocking 解析.

这段代码应该可以满足您的需求:

首先以Spring的方式获取对Resource的引用

  @Value("classpath:/sample.json")
  Resource sampleFile;

然后这样做:

return new Jackson2JsonDecoder()
        .decodeToMono(
            DataBufferUtils.read(sampleFile, new DefaultDataBufferFactory(), 4096),
            ResolvableType.forClass(MyPojo.class),
            null,
            null)
        .map(object -> (MyPojo) object)
        .map(MyPojo::getValues)

这样,您可以使用 DataBufferUtils.read 以 non-blocking 方式读取文件,并将 json 映射到您的 POJO。