有人知道如何编程地找出Java类加载器从何处加载该类吗?
我经常在大型项目中工作,在这些项目中,类路径非常长,手动搜索实际上不是一个选项。我最近遇到了一个问题,类加载器加载了一个不正确的类版本,因为它位于类路径的两个不同位置。
那么,如何让类加载器告诉我实际类文件在磁盘上的来源呢?
编辑:如果由于版本不匹配(或其他原因),类加载器实际上无法加载类,那么我们是否可以在读取之前找到它尝试读取的文件?
"我不认为jarrodroberson of this should be事情考虑到stackoverflow.com /问题/复制/ 11747833 & hellip;因为这是要在2008年的问题,问题是要在2012年
下面是一个例子:
package foo;
public class Test
{
public static void main(String[] args)
{
ClassLoader loader = Test.class.getClassLoader();
System.out.println(loader.getResource("foo/Test.class"));
}
}
打印出来:
file:/C:/Users/Jon/Test/foo/Test.class
为了减少冗余输入,还可以使用较短的版本:Test.class.getResource("Test.class"),它不重复包名。
如果类是从.groovy文件编译的,会怎么样?
@梅里顿:或者,为了生存重构:Test.class.getResource(Test.class.getSimpleName() +".class")。
但是,对于BouncyCastleProvider完整的包名是必需的。
getClassLoader()可以返回null。有关此方法的扩展,请参见此处。
@meriton Class#getResource(String name)委托给对象的类加载器,即ClassLoader#getResource(String name)方法。
同时,getResource可以返回空值。这个代码不会每次都起作用。
@汤姆和第225;?扎托:如果类可供类加载器使用,它就会工作。我同意如果OP需要处理类不可用的可能性,那么他们需要做一个空检查——这是一个简单的修改。
我用它来加载资源,这就是它失败的地方。具体地说,当我运行maven测试类时,它失败了——当时,我项目中的类试图从/target/test-classes而不是/target/classes加载资源。这个问题是通过使用new MyClass().getClass().getResource("...")或只是this.getClass ...(如果在实例化的上下文中)来解决的。
另一种方法是从(不操纵源)加载一个类的方法是用选项EDCOX1(2)启动Java VM。
这非常有效,并且不存在使用空类加载器处理类的问题。
我认为这应该是公认的答案。它确实为提出的问题提供了适当的解决方案。
@RIES如果不需要通过编程来实现这一点,这绝对是一种方法,它确实解决了我的问题。然而,该组织特别询问了如何通过程序实现这一点。
好吧,那只是把我从一个6小时的火花斯卡拉依赖地狱生活中拉出来。谢谢!
getClass().getProtectionDomain().getCodeSource().getLocation();
是的,尽管它不能在安装了安全管理器并且没有所需权限的情况下工作。
也可能是NPE…
仅供参考,npe=空指针异常。嗯!
只要您有一个实例的引用,这个方法是首选的,因为您可以从两个不同的位置加载同一个类。
当从Java 9 +模块调用(当然在2008中你不可能知道)时也不起作用。
这就是我们使用的:
public static String getClassResource(Class> klass) {
return klass.getClassLoader().getResource(
klass.getName().replace('.', '/') +".class").toString();
}
这将取决于类加载器的实现:getClass().getProtectionDomain().getCodeSource().getLocation()
当对象的ClassLoader注册为null时,jon的版本失败,这似乎意味着它是由启动ClassLoader加载的。
此方法处理该问题:
public static String whereFrom(Object o) {
if ( o == null ) {
return null;
}
Class> c = o.getClass();
ClassLoader loader = c.getClassLoader();
if ( loader == null ) {
// Try the bootstrap classloader - obtained from the ultimate parent of the System Class Loader.
loader = ClassLoader.getSystemClassLoader();
while ( loader != null && loader.getParent() != null ) {
loader = loader.getParent();
}
}
if (loader != null) {
String name = c.getCanonicalName();
URL resource = loader.getResource(name.replace(".","/") +".class");
if ( resource != null ) {
return resource.toString();
}
}
return"Unknown";
}
只编辑第一行:Main类。
Class> c = Main.class;
String path = c.getResource(c.getSimpleName() +".class").getPath().replace(c.getSimpleName() +".class","");
System.out.println(path);
输出:
/C:/Users/Test/bin/
也许风格不好,但效果很好!
通常,我们不知道使用什么硬编码。我们可以先获取类名,然后使用ClassLoader获取类URL。
String className = MyClass.class.getName().replace(".","/")+".class";
URL classUrl = MyClass.class.getClassLoader().getResource(className);
String fullPath = classUrl==null ? null : classUrl.getPath();
看看这个类似的问题。发现同一类的工具..
我认为最相关的障碍是如果您有一个定制的类加载器(从DB或LDAP加载)
这种方法适用于文件和JAR:
Class clazz = Class.forName(nameOfClassYouWant);
URL resourceUrl = clazz.getResource("/" + clazz.getCanonicalName().replace(".","/") +".class");
InputStream classStream = resourceUrl.openStream(); // load the bytecode, if you wish
假设您使用的是一个名为MyClass的类,那么下面的内容应该有效:
MyClass.class.getClassLoader();
是否可以获取.class文件的磁盘上位置取决于类加载器本身。例如,如果您使用的是BCEL,那么某个类甚至可能没有磁盘上的表示。
这将返回用于加载类的类加载器,不是吗?它找不到.class文件在哪里?
不,它不是。类加载器实际上可以重新传递到完全不同的类路径-意味着它将完全无法到达实际的类位置。