classloader getresource jar包资源冲突情况,父亲为大,兄弟之间,谁先加载谁牛逼
在class /classloader getResourceAsStream()与FileInputStream中,提出了一个问题:
类加载器中各jar包(包括父加载器)内资源冲突时,以谁为准,当时提出一个设想,认为:
父加载器——不一定本jar包(即执行代码的所在jar包)的子加载器所有jar包随机
本文通过实践验证,并得出最佳实践,即为class /classloader getResourceAsStream()与FileInputStream文中所言——
“所以从包名限定的角度说,前者比后者保险,假设2个jar包resource下都有资源文件a,则运行期具体拿哪个依托于类加载器加载顺序,但如果a有个性的包名,则冲突的可能性就大大降低”,当然如果resource中建立多级目录,达到的效果也是一样的
so使用class.getResource instead of class.getClassLoader.getResource
案例设计图如下:

*注意,第二个结果“self”有失准确
特点:
1 father.conf这个文件3个jar包中都有,文本分别为father、self、brother,以此测试是否会从父加载器先加载资源
2 self.conf这个文件仅有S SB两个同属于一个类加载器jar包有,以此来测试究竟会加载哪个,是否有规律
3 brother.conf这个文件仅有SB有,但会在S的代码中去调用,以此来测试a jar包是否能调用到b jar包的资源,只要双方在同一个类加载器下
代码:
public class LcProperty {
public static String read(String conf) throws IOException {
System.out.println(LcProperty.class.getClassLoader().getResource(conf));
InputStream inputStream = LcProperty.class.getClassLoader().getResourceAsStream(conf);
byte [] bytes = new byte[20];
inputStream.read(bytes);
String out = new String(bytes);
System.out.println(out);
return out;
}
}
这个类就是图中的S
/*
故意让brother在前面,以此证明即使在sub.jar中调用getresource也不会优先查
sub中的资源或类,而会去查被优先加载的brother.jar
这个加载顺序取决于操作系统
*/
String dirSub = "file:/Users/sunyuming/Documents/tool/jars//MySub-1.0.0-jar-with-dependencies.jar";
String dirSubBro = "file:/Users/sunyuming/Documents/tool/jars//MySubBrother-1.0.0-jar-with-dependencies.jar";
URL urlSub = new URL(dirSub);
URL urlSubBro = new URL(dirSubBro);
URLClassLoader cl1 = new URLClassLoader(new URL[]{urlSub, urlSubBro});
Class c1 = cl1.loadClass("lcproperty.LcProperty");
Method method1 = c1.getMethod("read", String.class);
method1.invoke(null, "father.conf");
method1.invoke(null, "self.conf");
method1.invoke(null, "brother.conf");
URLClassLoader cl2 = new URLClassLoader(new URL[]{urlSubBro, urlSub});【重要,放前面的先加载】
Class c2 = cl2.loadClass("lcproperty.LcProperty");
Method method2 = c2.getMethod("read", String.class);
method2.invoke(null, "father.conf");
method2.invoke(null, "self.conf");
method2.invoke(null, "brother.conf");
这个类是图中的S
输出:
file:/Users/joyce/work/MyTest/MyMain/target/classes/father.conf
father
jar:file:/Users/sunyuming/Documents/tool/jars//MySub-1.0.0-jar-with-dependencies.jar!/self.conf
self
jar:file:/Users/sunyuming/Documents/tool/jars//MySubBrother-1.0.0-jar-with-dependencies.jar!/brother.conf
brother
file:/Users/joyce/work/MyTest/MyMain/target/classes/father.conf
father
jar:file:/Users/sunyuming/Documents/tool/jars//MySubBrother-1.0.0-jar-with-dependencies.jar!/self.conf
brother
jar:file:/Users/sunyuming/Documents/tool/jars//MySubBrother-1.0.0-jar-with-dependencies.jar!/brother.conf
brother
结论:
1 father.conf毫无疑问,每次都确定会先到父加载器寻找,从代码看也是如此
public URL getResource(String name) {
URL url;
if (parent != null) {
url = parent.getResource(name);
} else {
url = getBootstrapResource(name);
}
if (url == null) {
url = findResource(name);
}
return url;
}
2 self.conf 两次输出不一样,取决于类加载器先加载到哪个jar
3 brother.conf ,也毫无疑问的,SB的资源被从S的jar文件中的代码getResource到
浙公网安备 33010602011771号