简体   繁体   English

Java ClassLoader更改

[英]Java ClassLoader change

I have some class A : 我有一些A类:

public class A {
    public A(String str) {
        System.out.println("Create A instance: " + str);
    }

    public void methodA() {
        System.out.println("#methodA1()");
    }
}

And my class loader implementation: 我的类加载器实现:

public class MyClassLoader extends ClassLoader {
    public MyClassLoader() {    
        super();
    }

    @Override
    public synchronized Class<?> loadClass(String name) 
            throws ClassNotFoundException {

        System.out.println("Load: " + name);

        return super.loadClass(name);
    }
}

And now I try to change default class loader in current thread: 现在我尝试更改当前线程中的默认类加载器:

import java.util.ArrayList;
import java.util.List;

public class ChangeLoaderTest {
    public static void main(String[] args) {
        // Save class loader so that we can restore later.
        ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();

        MyClassLoader newLoader = new MyClassLoader();
        try {
            // Set new classloader.
            Thread.currentThread().setContextClassLoader(newLoader);

            // My class.
            A a = new A("1");
            a.methodA();

            // Standard Java class.
            List<Integer> list = new ArrayList<Integer>();
            list.add(2);
            list.add(3);
        } finally {
            // Restore.
            Thread.currentThread().setContextClassLoader(oldLoader);
        }
    }
}

And ChangeLoaderTest output: ChangeLoaderTest输出:

Create A instance: 1
#methodA1()

No one 没有人

Load: ...

Why? 为什么? How I can change ClassLoader into some thread? 我如何将ClassLoader更改为某个线程?

As Marko Topolnik points out the context classloader is for use by frameworks . 正如Marko Topolnik指出的那样, 上下文类加载器是供框架使用的 To use the classloader yourself you have to call loadClass("somepackage.A") and then use the reflection API to create a new instance of A ( Class.newInstance() ). 要自己使用类加载器,必须调用loadClass("somepackage.A") ,然后使用反射API创建A的新实例( Class.newInstance() )。

You wont be able to use A or its methods in your source directly since the calling code does not know A - it uses a different classloader. 由于调用代码不知道A - 它使用不同的类加载器,因此您无法直接在源代码中使用A或其方法。 An interface or baseclass of A that can be loaded by the normal classloader can be used to avoid reflection. 可以由普通类加载器加载的A的接口或基类可用于避免反射。

interface AIF{
        void someMethod();
 }
class A implements AIF{
      public void someMethod(){}
 }


public void test(){
     MyLoader loader = new MyLoader();
     Class cla = loader.loadClass("A");
     AIF a = (AIF) cla.newInstance();
     a.someMethod();

 }

The contextClassLoader mechanisms is not used by the basic Java operations like new . contextClassLoader机制被像new这样的基本Java操作使用。 It's only there so various frameworks can access the context class loader in charge and load resources, classes, etc. Java will always use the classloader that loaded the code that is executing. 只有这样,各种框架才能访问负责的上下文类加载器并加载资源,类等.Java将始终使用加载正在执行的代码的类加载器。 It's the one that you access via ChangeLoaderTest.class.getClassLoader() -- and there is nothing you can do about this one. 它是您通过ChangeLoaderTest.class.getClassLoader()访问的那个 - 并且您无法对此进行任何操作。

I think that what happens is that your application's class loader which is also your classloader's "parent" can locate A and load it. 我认为发生的事情是你的应用程序的类加载器也是你的类加载器的“父”可以找到A并加载它。 As a result your classloader will not be searched or used for loading A . 因此,您的类加载器将不会被搜索或用于加载A

To be honest, I haven't much experience with classloaders but if you subclassed one that uses a URL for the path of the class (so that it can locate the class file) and the parent classloader can not load it (not part of classpath), your custom one will be used. 说实话,我对类加载器的经验不多,但是如果你继承了一个使用URL作为类路径的子类(以便它可以找到类文件),那么父类加载器就无法加载它(不是类路径的一部分) ),将使用您的自定义。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM