无法创建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