无法创建cutom类加载器
我正在尝试创建一个自定义类加载器来完成以下操作:
我在包com.company.MyClass
有一个类
当类加载器被要求以以下格式加载任何东西时:
com.company.[additionalPart].MyClass
我想让类加载器有效地加载com.company.MyClass
忽略包名的[additionalPart]。
这里是我有的代码:
public class MyClassLoader extends ClassLoader {
private String packageName = "com.company.";
final private String myClass = "MyClass";
public MyClassLoader(ClassLoader parent) {
super(parent);
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
Class<?> clazz = null;
String className = name;
// Check if the class name to load is of the format "com.company.[something].MyClass
if (name.startsWith(packageName)) {
String restOfClass = className.substring(packageName.length());
// Check if there is some additional part to the package name
int index = restOfClass.indexOf('.');
if (index != -1) {
restOfClass = restOfClass.substring(index + 1);
//finally, check if the class name equals MyClass
if (restOfClass.equals(myClass)) {
// load com.company.MyClass instead of com.company.[something].MyClass
className = packageName + myClass;
clazz = super.loadClass(className, true);
}
}
}
if (clazz == null) {
// Normal clase: just let the parent class loader load the class as usual
clazz = super.loadClass(name);
}
return clazz;
}
}
这里是我的测试代码:
public class TestClassLoader {
public void testClassLoader () throws Exception {
ClassLoader loader = new MyClassLoader(this.getClass().getClassLoader());
clazz = Class.forName("com.company.something.MyClass", true, loader );
}
public static void main (String[] args) throws Exception {
TestClassLoader tcl = new TestClassLoader();
tcl.testClassLoader();
}
}
MyClassLoader获取正确的类(即com.company.MyClass
),并从loadClass
(我已经遍历代码)正确地返回它,但是,它在稍后的某个点(即在从JVM调用loadClass
之后)引发异常,如下:
线程“main”中的异常java.lang.ClassNotFoundException:com / company / something / MyClass at java.lang.Class.forName0(Native Method)
在[我的代码]在java.lang.Class.forName(Class.java:247)
现在,我意识到你们中的一些人可能会想:“为什么有人需要这样做呢?必须有更好的方式”。 我确信有,但是这对我来说是一种教育,因为我想了解类加载器是如何工作的,并且对jvm类加载过程有更深入的了解。 所以,如果你可以忽略程序的无聊,并且幽默我,我会非常感激。
那么,有没有人有任何想法?
谢谢!
你的问题
这是纯粹的猜测。 类名称存储在java字节码中。 因此,您使用这种技术加载的类将会有缺陷。 这可能使系统混淆。
ClassLoader可能会保留对com.company.something.MyClass的引用,但类本身可能会保留对com.company.MyClass的引用。 (我使用的可能很多,因为我确实不太确定。)可能一切正常,直到你使用MyClass类为止。 那么不一致就会产生麻烦。 那么这个异常什么时候抛出?
如果您有兴趣了解类加载器如何工作,那么您可以使用javap来获取字节码。 这也可以让你检查我的假设。
如果我的假设是正确的,那么解决方案就是修复字节码。 有几个包允许您设计字节码。 复制类,更改复制的类的名称,然后加载它。
在旁边
虽然与您的问题无关:我发现以下内容不必要的复杂(并且它不适用于com.company.something.somethingelse.MyClass)。
// Check if the class name to load is of the format "com.company.[something].MyClass
if (name.startsWith(packageName)) {
String restOfClass = className.substring(packageName.length());
// Check if there is some additional part to the package name
int index = restOfClass.indexOf('.');
if (index != -1) {
restOfClass = restOfClass.substring(index + 1);
//finally, check if the class name equals MyClass
if (restOfClass.equals(myClass)) {
// load com.company.MyClass instead of com.company.[something].MyClass
className = packageName + myClass;
clazz = super.loadClass(className, true);
}
}
为什么不?
//Check if the class name to load is of the format "com.com // Check if the class name to load is of the format "com.company.[something].MyClass"
if ( ( name . startsWith ( packageName ) ) && ( name . endsWith ( myClass ) ) )
我不认为你可以通过类加载器来实现。 理论上,如果某个其他类尝试加载它假定被称为“com.mycompany.foo.MyClass”的类,那么为时已晚,有人已经有一个字节码引用“com.mycompany.foo”的类,并且该类已加载。
通过使用类似ASM的东西在构建时重新打包所有代码,重新打包在静态级别更容易。 你当然必须修改他自己的类和我引用这个包的所有类。
如果您使用Maven,请查看阴影插件。 如果不是,我似乎记得一个名为JarJar的工具。
您当然可以在运行时通过javaagent和ClassTransformer进行这种字节码操作。 maven-shade-plugin的代码实际上非常小 - 如果你抓住它并且撕掉了maven部分,你可能会在2-3天内有所作为。
链接地址: http://www.djcxy.com/p/58267.html上一篇: Trouble creating cutom class loader
下一篇: How do I get a list of all package names loaded by the JVM