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

Posted

技术标签:

【中文标题】无法在 docker 容器内以非阻塞方式读取类路径资源文件【英文标题】:Unable to read classpath resource file in non-blocking way inside docker container 【发布时间】:2020-11-29 21:49:41 【问题描述】:

我正在尝试从 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 build 来构建 jar 文件,然后从中构建 docker 映像)

部分错误堆栈跟踪:

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

【问题讨论】:

检查 wnated 资源是否是 Docker 容器内的类路径。也许你必须将它添加到你的 Dockerfile 中:docs.docker.com/engine/reference/builder/#add Simon 的解决方案也是使用阻塞 I/O,所以如果您在这里使用 Flux 没有任何好处,那么您可以使用 inputstream 以常规阻塞方式读取文件并将工作卸载到弹性调度程序. 这能回答你的问题吗? Reactive way to read and parse file from resources using WebFlux? 【参考方案1】:

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

您可以参考以下关于相同内容的 *** 讨论:

    这个answer 回复this question 回复this question

我认为您应该看看 Spring 的 this class,它利用非阻塞解析将字节流解码为 JSON 并使用 Jackson 2.9 转换为 Object's。

此代码应该满足您的需求:

首先以 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以非阻塞方式读取文件,并将json映射到您的POJO。

【讨论】:

以上是关于无法在 docker 容器内以非阻塞方式读取类路径资源文件的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Docker 容器中以非 root 用户身份启动 cron?

如何以非阻塞、不可中断的方式从类中运行 C++ 函数 [关闭]

如何在 docker 中以非 root 用户身份写入卷容器?

使用 Matplotlib 以非阻塞方式绘图

以非阻塞方式打开 QDialog

如何以非阻塞方式处理 websocket 数据?