Java 如何找到类加载器加载了哪些 jar 以及以什么顺序加载?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2179858/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to find which jars and in what order are loaded by a classloader?
提问by Marina
I could not find a clear answer to this question elsewhere, so I'll try here:
我在其他地方找不到这个问题的明确答案,所以我会在这里尝试:
Is there some way (programmatic or other) to get a list of JARs/classes loaded by an Application Classloader in the precise order they were loaded? By Application Classloader I mean the classloader that loads an EAR application in an applications server (WLS, WAS, JBoss...), but obviously, it applies to any classloader.
是否有某种方法(编程或其他)可以按照加载的精确顺序获取应用程序类加载器加载的 JAR/类列表?应用程序类加载器是指在应用程序服务器(WLS、WAS、JBoss...)中加载 EAR 应用程序的类加载器,但显然,它适用于任何类加载器。
So, to generalize, what I would like to find out is the list and order of JARs loaded by a specified classloader. Not individual classes, that is easy enough to find out by calling the classloader.getPackages(), but a list of JAR files that were loaded by this classloader.
所以,概括地说,我想知道的是指定类加载器加载的 JAR 的列表和顺序。不是单个类,通过调用 classloader.getPackages() 很容易找到,而是由这个类加载器加载的 JAR 文件的列表。
采纳答案by kdgregory
The short answer is no. Classloaders are not required to expose their search logic.
最简洁的答案是不。类加载器不需要公开它们的搜索逻辑。
However, if your classloader instance happens to be URLClassLoaderor a subclass, then you do have access to the list of jars/directories, via the getURLs()
method. Per the doc for this class, those URLs will be searched in order.
但是,如果您的类加载器实例恰好是URLClassLoader或子类,那么您确实可以通过该getURLs()
方法访问 jars/目录列表。根据此类的文档,将按顺序搜索这些 URL。
In practice, if you're trying to find out where a class is being loaded from, Steve's answer is probably more useful.
在实践中,如果您试图找出从何处加载类,Steve的回答可能更有用。
回答by Steve
Have you tried to use the JVM option -verbose:class
. It displays all loaded JAR files and classes.
您是否尝试过使用 JVM 选项-verbose:class
。它显示所有加载的 JAR 文件和类。
Example:
例子:
[Opened C:\Program Files\JDK160~1\jre\lib\rt.jar]
[Loaded java.lang.Object from C:\Program Files\JDK160~1\jre\lib\rt.jar]
回答by gmournos
Go through the Protection Domain of the class (the location/certificate combination). e.g. for PDFParser.class you get it like this...
浏览类的保护域(位置/证书组合)。例如,对于 PDFParser.class,你会像这样得到它......
PDFParser.class.getProtectionDomain().getCodeSource().getLocation().toString()
If it is loaded from the jre classes or from endorsed dirs it will throw an exception cos these classes load without protection...
如果它是从 jre 类或从背书目录加载的,它将抛出异常,因为这些类在没有保护的情况下加载...
回答by MMKarami
As an alternative way, you can use this code snippet. The result is a file that consist of related jar files to a class-loader and class files that are loaded by an object's class-loaders (chain of class-loaders including its parents until root class-loader). Class-loaders are seperated by stars.
作为替代方法,您可以使用此代码片段。结果是一个文件,其中包含与类加载器相关的 jar 文件和由对象的类加载器加载的类文件(类加载器链,包括其父类,直到根类加载器)。类加载器由星号分隔。
Object obj = this;
ClassLoader classLoader = obj.getClass().getClassLoader();
File file = new File("classlodersClassesJars.txt");
if(file.exists()) {
file.delete();
}
if(classLoader != null) { // to escape from system classes that are loaded by bootstrap class-loader such as String.
do {
try {
Class clClass = classLoader.getClass();
while(clClass != ClassLoader.class){
clClass = clClass.getSuperclass();
}
java.lang.reflect.Field domainField = clClass.getDeclaredField("domains");
java.lang.reflect.Field classesField = clClass.getDeclaredField("classes");
domainField.setAccessible(true);
classesField.setAccessible(true);
HashSet domains = (HashSet<String>) domainField.get(classLoader);
Vector classes = (Vector) classesField.get(classLoader);
FileOutputStream fos = new FileOutputStream("classlodersClassesJars.txt", true);
fos.write(("\n******************** " + classLoader.toString() + "\n").getBytes());
fos.write(Arrays.toString(classes.toArray()).getBytes());
Object[] reverseDomains = domains.toArray();
org.apache.commons.lang.ArrayUtils.reverse(reverseDomains);
fos.write(Arrays.toString(reverseDomains).getBytes());
fos.close();
classLoader = classLoader.getParent();
} catch (Exception exception) {
exception.printStackTrace();
// TODO
}
} while (classLoader.getParent() != null);
}