写在前边
这阵子有点忙,开发一个微服务项目中读取配置文件的时候在本地测试是可以的,但是一到测试环境就报错,经查看发现是因为发布的时候是用的war包,使用java -jar xxx.war
启动的,所以用当前类名.class.getResource("/路径")
的方式拿到的是一个URL,其中,URL里有!
,无法成功toURI.
出问题的代码:
static { //静态加载公私钥到成员变量,减少开流 try { File privateKeyFile = new File(WebRTCSigApiUtil.class.getResource("/private_key").toURI()); byte[] privateKey = new byte[(int) privateKeyFile.length()]; //读取私钥的内容 FileInputStream in1 = new FileInputStream(privateKeyFile); in1.read(privateKey); in1.close(); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("WebRTCSigApiUtil初始化出现错误"); } }
原因分析
其中当前类名.class.getResource("/private_key")
获取的是这个文件的URL,File类的构造方法只支持文件全路径或URI,所以我们需要URL转换成URI,这里在打成war包的情况下,转换成URI会报java.lang.IllegalArgumentException: URI is not hierarchical
的错误,因为是在静态块中报错,所以会停止继续加载类,Classloader在classpath下可以找到这个类,但是却加载不了,从而抛出java.lang.NoClassDefFoundError:could not initial class xxxxxxxxxxxx
的异常
解决办法
这里只提供获取非配置文件中的内容的方法,比如private_key文件,我们的目的是读取出文件中的内容,所以完全可以不用使用File类进行二次包装,我们需要的内容直接从流中就可以获取。
static { //静态加载公私钥到成员变量,减少开流 String privateKey = ""; try { Resource privateKeyResource = new ClassPathResource("private_key"); privateKey = new String(FileCopyUtils.copyToByteArray(privateKeyResource.getInputStream())); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("WebRTCSigApiUtil初始化出现错误"); } }
//上面代码导入的包import org.springframework.core.io.ClassPathResource;import org.springframework.core.io.Resource;import org.springframework.util.FileCopyUtils;
这里的private_key文件处于resources下,resources正处于classpath下,打成war之后,这个路径所有classpath路径下的文件都会被复制到class目录下
通过使用Spring的 ClassPathResource 读取出classpath下的文件资源
然后通过资源获取流,使用FileCopyUtils进行转换成byte[],
最后通过String的构造方法将字节数组转成String对象,此时这个 privateKey 中所保存的内容就是文件中的内容了