无法在 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讨论:
- 这个answer
- 对
的回答
- 对 this question
的回答
我认为你应该看一下 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。
我正在尝试从 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讨论:
- 这个answer
- 对
- 对 this question 的回答
我认为你应该看一下 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。