问题背景
前期针对一个使用微服务做了发动脚本的参数优化,在本地环境发动运转好好的,但是上了DEV环境后,跑到一个获取资源文件的时候报资源找不到,类似于下面的报错
java.io.FileNotFoundException: aa.txt
at com.hyw.util.ResourceUtil.getTextContent(ResourceUtil.java:27)
at com.toby.sharding.jdbc.source.start.PointShardingApplication.main(PointShardingApplication.java:41)
发动脚本优化前期有文章讲过,详细能够参阅这篇落地实践之JAVA使用发动脚本
要害发动脚本参数如下:
setjvment.sh
# 设置java.ext.dirs JAVA_OPTS="$JAVA_OPTS -Djava.ext.dirs=$JAVA_HOME/jre/lib/ext:$work_home/lib"
start.sh
CLASSPATH=$CLASSPATH:$work_home/lib/conf
问题重现
编写相关问题代码,新增ResourceUtil
用来获取资源文件
public class ResourceUtil {
private static ResourceUtil resourceUtil = new ResourceUtil();
public static ResourceUtil getInstance() {
return resourceUtil;
}
public String getTextContent(String fileName) throws FileNotFoundException {
URL url = ResourceUtil.class.getClassLoader().getResource(fileName);
System.out.println("default class loader=" ResourceUtil.class.getClassLoader());
if (Objects.isNull(url)) {
System.out.println("default not found");
url = ClassLoader.getSystemResource(fileName);
System.out.println("app not found,class loader=" ResourceUtil.class.getClassLoader());
}
if (Objects.isNull(url)) {
throw new FileNotFoundException(fileName);
}
InputStream in = null;
try {
in = url.openStream();
} catch (IOException e) {
e.printStackTrace();
}
BufferedReader bf = new BufferedReader(new InputStreamReader(in));
StringBuilder st = new StringBuilder();
String line = "";
try {
while ((line = bf.readLine()) != null) {
st.append(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
bf.close();
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println(fileName " context=" st.toString());
return st.toString();
}
@Test
public void testCase01() throws FileNotFoundException {
String content = ResourceUtil.getInstance().getTextContent("a.txt");
System.out.println(content);
}
}
新增了两个资源文件
直接在发动类中获取这两个资源文件
try {
ResourceUtil.getInstance().getTextContent("a.txt");
ResourceUtil.getInstance().getTextContent("conf/b.txt");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
打包上传后在windows下运转结果如下:
default class loader=sun.misc.Launcher$ExtClassLoader@4b85612c
a.txt context=123
default class loader=sun.misc.Launcher$ExtClassLoader@4b85612c
conf/b.txt context=b.txt
在windows下运转是ok的,但是在unix下确实不行,unix下的截图无法考出来,大约运转结果如下
default class loader=sun.misc.Launcher$ExtClassLoader@4b85612c
a.txt context=123
default class loader=sun.misc.Launcher$ExtClassLoader@4b85612c
default not found
app not found,class loader=sun.misc.Launcher$AppClassLoader@4b85612c
conf/b.txt context=b.txt
使用这个class默认的classloader获取不到资源文件,打印出class loader可知是ExtClassLoader
ExtClassLoader
是Java中的一个类加载器,它是Java类加载器层次结构中的一部分。其全名为”Extension Class Loader”,首要用于加载Java的扩展类库。
因而,按照上述所说,ExtClassLoader不应该加载事务jar,一起能够看出a.txt
其实是在另一个jar包中的,也读取不出来,阐明ExtClassLoader不适合加载资源文件,详细JDK源码还没细看
修正计划
修正发动脚本,将事务使用的jar都放在app class loader下,即用-cp关联事务jar
setjvment.sh
删去设置java.ext.dirs
start.sh
修正如下
CLASSPATH=$CLASSPATH:$work_home/lib/conf
for file in $work_home/lib/*.jar
do
if test -f $file
then
CLASSPATH=$CLASSPATH:$file
fi
done
修正完之后运转正常,能够获取资源文件
回忆
为什么本地IDEA运转OK?
抛开系统问题,发动本地使用jps查看发动参数
7968 com.toby.sharding.jdbc.source.start.PointShardingApplication -XX:TieredStopAtLevel=1 -Xverify:none -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true -javaagent:D:toolsJetBrainsIntelliJ IDEA 2021.3.3libidea_rt.jar=53161:D:toolsJetBrainsIntelliJ IDEA 2021.3.3bin -Dfile.encoding=UTF-8
使用arthas追寻jvm参数,使用jar和resource应该都在class-path下
因而不会有问题
加载资源的办法
有两种办法一个是Class类,另一个是ClassLoader类 详细能够参阅这篇文章 Java加载资源文件的两种办法