无法读取spring boot打包jar文件 [英] Can not read spring boot packaging jar file

查看:48
本文介绍了无法读取spring boot打包jar文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

环境:Ubuntu 18 + Spring boot 2.0 + JDK 11

Environment: Ubuntu 18 + Spring boot 2.0 + JDK 11

应用程序在 IntelliJ 中运行时正确执行,但在 Spring boot maven 插件打包文件后读取文件时无法正确执行.

It performs correctly when the application runs in IntelliJ, but it doesn't when reading the file after Spring boot maven plugin packaging file.

PS:确实可以在打包的jar文件中找到该文件!

PS: The file indeed could be found in the packaged jar file!

java.io.FileNotFoundException: class path resource [jmxremote.password] 
cannot be resolved to absolute file path because it does not reside in the 
file system: jar:file:/home/XXX/YYY/target/YYY-1.0-Final.jar!/BOOT-
INF/classes!/jmxremote.password

推荐答案

TL;DR

在 Spring Framework 环境中,专注于使用 Spring 实用工具来处理资源(例如 ResourceUtils),它很好地封装了较低级别的操作系统相关 IO 操作.ResourceUtils 已经包含多个陷阱,用于确定您正在运行的项目是爆炸(在 IDE 中运行)还是打包(在 JAR 文件中)).

In the Spring Framework environment focus on using Spring utility tooling for handling resources (like the ResourceUtils class) which nicely encapsulate lower-level, operating system dependent IO operations. The ResourceUtils already contains multiple traps to figure out if the project you are running is exploded (run in IDE) or packaged (inside a JAR file).

Karol 提供的答案似乎是最简单的并且相对防弹,直到您需要一定程度的灵活性来指定文件位置(在 jar 文件内,但可以在外部定义它并在文件系统中的某个位置提供)).那么使用 getResourceAsStream() 方法的方法将不起作用.

The answer provided by Karol seems the easiest and is relatively bullet-proof, until you need a certain level of flexibility to specify file location (inside a jar file but with the possibility to define it externally and provide somewhere in the file system). Then the approach with getResourceAsStream() method won't work.

标准 Java IO (java.nio) 使用 FileSystemProvider 类来委托 IO 操作(如创建、读取和删除文件).

Standard Java IO (java.nio) is using FileSystemProvider classes to delegate IO operations (like creating, reading and deleting files).

提供者由 URI scheme 标识.默认提供程序由 URI 方案文件"标识.它创建 FileSystem,提供对 Java 虚拟机可访问的文件系统的访问.FileSystems 类定义了文件系统提供程序的定位和加载方式.

A provider is identified by a URI scheme. The default provider is identified by the URI scheme "file." It creates the FileSystem that provides access to the file systems accessible to the Java virtual machine. The FileSystems class defines how file system providers are located and loaded.

因此,如果您的文件位于文件系统的某个位置,则没有问题,并且一切正常.从技术上讲,Application.class.getResource("").toURI() 返回的 URL 以 file:// 开头并包含有效的文件系统路径.

So, if your file is somewhere on the filesystem, there are no issues, and everything works fine. Technically, the URL returned by Application.class.getResource("").toURI() starts with file:// and contains a valid filesystem path.

话虽如此,当您的文件着陆"在 jar 文件中时,Application.class.getResource("").toURI() 返回的内容更类似于 file://{jar-location}!/(注意感叹号),这不是有效的文件模式路径,Java 不知道如何处理它.需要注册一个额外的文件系统提供者.

Having said that, when your file "land" inside a jar file, the Application.class.getResource("").toURI() returns something more like file://{jar-location}!/ (mind the exclamation mark), which is not a valid file schema path and Java doesn't know how to handle it. An additional file system provider needs registering.

FileSystems.newFileSystem(uri, emptyMap());

Java 计算出(基于 URI)方案并注册一个新的文件系统.从现在开始,可以使用标准的java.nio 文件操作.

Java figures out (based on URI) the scheme and registers a new file system. From now on, standard java.nio file operations can be used.

例如,如果您在 /webapp 文件夹中有一些文件,这些文件可以(但不需要)位于 jar 文件中,并且您想列出它们.

For example, if you have some files in a /webapp folder which can (but don't need to) be inside a jar file and you'd like to list them.

// Load zip specific filesystem provider when run from inside a fat-jar
URI uri = Application.class.getResource("").toURI();
if (uri.toString().contains("!")) {
    FileSystems.newFileSystem(uri, emptyMap());
}

URI rootFolder = Application.class.getResource("/webapp").toURI();
List<Path> banners = Files.list(Paths.get(rootFolder))
        .collect(Collectors.toList());

Random rand = new Random();
Path path = banners.get(rand.nextInt(banners.size()));

log.info("Random image: {}", path.getFileName());
byte[] bytes = Files.readAllBytes(path);

新文件系统提供程序的安装是全局性的,应该只安装一次.

Installation of a new file system provider is global and should be done only once.

这篇关于无法读取spring boot打包jar文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆