我有两个类(A和B)由不同的加载ClassLoaders.此外,我有第三个类,它提供静态getter和setter方法.我希望以下图片可以澄清情况:

该Data课程如下:
public class Data {
private static String data = "<fill in>";
public static void setData(String d) {
data = d;
}
public static String getData() {
return data;
}
}
Run Code Online (Sandbox Code Playgroud)
在课堂上A,我想设置静态值,Data在B我想要检索这个值.但是,B我总是得到原始值(即"<fill in>").我只对ClassLoaders 有基本的了解,所以我不太清楚引擎盖下发生了什么.我认为ClassLoaders(clA和clB)都将传播到它们的父级ClassLoader,并且我将Data在两者中获得相同的类.任何人都可以给我一些关于行为的反馈或指出我的方向来看待?
当我打印这hashCode()两个Data类时,我得到了不同的值(意思是显然我不能访问同一个类).是否有简单的方法来说明ClassLoader层次结构?
小智 4
如果您的问题是如何说明或可视化对象的类加载器层次结构,那么您可以在代码中遍历每个类的类加载器。您提到您正在使用 groovy,因此示例如下:
def showObjectClassLoaderHierarchy(Object obj) {
def classLoader = showClassLoaderHierarchy(obj.getClass().getClassLoader());
showClassLoaderHierarchy(classLoader);
}
def showClassLoaderHierarchy(ClassLoader loader) {
if (loader != null) {
println "Classloader: " + loader.hashCode();
while (loader.getParent() != null) {
loader = loader.getParent();
println " Child of: " + loader.hashCode();
}
}
}
Run Code Online (Sandbox Code Playgroud)
我想你会发现,在你的代码中,两个 Data 对象实际上不是从同一个类加载器加载的,这就是为什么它们有不同的静态变量。
我整理了一个样本
我看到虽然 LoadA 和 LoadB 有不同的类加载器,但 DataObj 和静态变量来自公共类加载器。
完整代码位于: https: //github.com/lucasmcgregor/groovy_classloader_test
groovy 中的主要对象:
import java.lang.ClassLoader;
import java.net.URLClassLoader;
import java.net.URL;
def showObjectClassLoaderHierarchy(Object obj) {
def classLoader = showClassLoaderHierarchy(obj.getClass().getClassLoader());
showClassLoaderHierarchy(classLoader);
}
def showClassLoaderHierarchy(ClassLoader loader) {
if (loader != null) {
println "Classloader: " + loader.hashCode();
while (loader.getParent() != null) {
loader = loader.getParent();
println " Child of: " + loader.hashCode();
}
}
}
println "Setting up child classLoaders A and B...";
def URL[] urlsA = [new URL("file:///tmp/cla/")];
def classLoaderA = new URLClassLoader(urlsA, this.getClass().getClassLoader());
def URL[] urlsB = [new URL("file:///tmp/clb/")];
def classLoaderB = new URLClassLoader(urlsB, this.getClass().getClassLoader());
println "Classloader A heirachry:";
showClassLoaderHierarchy(classLoaderA);
println "Classloader B: ";
showClassLoaderHierarchy(classLoaderB);
println "";
println "Now loading Load classes A and B from seperate classloaders:";
def loadA = classLoaderA.loadClass("LoadA").newInstance();
def loadB = classLoaderB.loadClass("LoadB").newInstance();
print "LoadA: heirachry";
showObjectClassLoaderHierarchy(loadA);
print "LoadB: heirachry";
showObjectClassLoaderHierarchy(loadB);
println "";
println "Now pulling the data objects from both and comparing classloders and static data: ";
def dobjA = loadA.getDataObj();
def dobjB = loadB.getDataObj();
println "dataA static field:" + dobjA.getData();
println "dataA static field hashcode: " + dobjA.getData().hashCode();
println "dataA hashcode: " + dobjA.hashCode();
println "dataA classloader: ";
showObjectClassLoaderHierarchy(dobjA);
println "dataB static field: " + dobjB.getData();
println "dataB static field hashcode: " + dobjB.getData().hashCode();
println "dataB hashcode: " + dobjB.hashCode();
println "dataB classLoader:";
showObjectClassLoaderHierarchy(dobjB);
Run Code Online (Sandbox Code Playgroud)
结果是:
Setting up child classLoaders A and B...
Classloader A heirachry:
Classloader: 1926764753
Child of: 1163157884
Child of: 1022308509
Classloader B:
Classloader: 846238611
Child of: 1163157884
Child of: 1022308509
Now loading Load classes A and B from seperate classloaders:
LoadA: heirachryClassloader: 1926764753
Child of: 1163157884
Child of: 1022308509
LoadB: heirachryClassloader: 846238611
Child of: 1163157884
Child of: 1022308509
Now pulling the data objects from both and comparing classloders and static data:
dataA static field:Loaded By B
dataA static field hashcode: 1828548084
dataA hashcode: 2083117811
dataA classloader:
Classloader: 1163157884
Child of: 1022308509
dataB static field: Loaded By B
dataB static field hashcode: 1828548084
dataB hashcode: 157683534
dataB classLoader:
Classloader: 1163157884
Child of: 1022308509
Run Code Online (Sandbox Code Playgroud)
您会看到 LoadA 和 LoadB 都有不同的类加载器,但它们共享一个父类加载器。
父类加载器为 LoadA.dataObj 和 LoadB.dataObj 的两个实例加载 DataObj。
LoadA.dataObj 和 LoadB.dataObj 具有不同的哈希码。
但是,LoadA.dataObj.data 和 LoadB.dataObj.data 具有相同的哈希码,因为这是静态对象。它们也具有相同的价值。LoadB 最后实例化它的 dataObj 并将字符串设置为“Loaded By B”