【问题标题】:Java ClassLoader changeJava 类加载器更改
【发布时间】:2014-03-04 23:25:41
【问题描述】:

我有一些课A:

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

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

还有我的类加载器实现:

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);
    }
}

现在我尝试更改当前线程中的默认类加载器:

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);
        }
    }
}

ChangeLoaderTest 输出:

Create A instance: 1
#methodA1()

没有人

Load: ...

为什么?如何将ClassLoader 更改为某个线程?

【问题讨论】:

  • “我有一些 A 类:” 虽然有些人认为将问题“抽象”到可以表达为钝符号的程度更好,但我更喜欢一些有助于解释类 A 中的内容的上下文,这使您想要动态加载它。 IE。 A 类可能是 UserDefinedPlugIn - 后者提供了一些上下文,前者没有。
  • 好的,我可以解释一下这个问题的上下文。我有将图像读入BufferedImage 的课程。有时是ImageIO.read(file),有时是Sanselan.getBufferedImage(file)。我有自己的保存图像的类,我应该从文件创建BuffredImage,然后将数据从BufferedImage 复制到我的对象。我想使用一些代理类来捕获所有#get(...) 方法调用以将信息保存在我的对象中。

标签: java classloader


【解决方案1】:

正如 Marko Topolnik 指出的 context classloader is for use by frameworks。要自己使用类加载器,您必须调用 loadClass("somepackage.A"),然后使用反射 API 创建 A 的新实例 (Class.newInstance())。

您不能直接在源代码中使用 A 或其方法,因为调用代码不知道 A - 它使用不同的类加载器。可以通过普通类加载器加载的 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();

 }

【讨论】:

  • 不幸的是,您不能像 vanveber 那样在接口(与此相关的任何构造函数)中定义非默认构造函数。所以,进入反思......
  • @mazaneicha 你可以通过创建工厂类和工厂接口来绕过它(只有当你真的讨厌反射时)。
【解决方案2】:

contextClassLoader 机制new 等基本 Java 操作使用。只有在那里,各种框架才能访问负责的上下文类加载器并加载资源、类等。Java 将始终使用加载正在执行的代码的类加载器。您可以通过ChangeLoaderTest.class.getClassLoader() 访问它——您对此无能为力。

【讨论】:

    【解决方案3】:

    我认为发生的情况是您的应用程序的类加载器(也是您的类加载器的“父级”)可以找到A 并加载它。因此,您的类加载器将不会被搜索或用于加载A

    老实说,我对类加载器没有太多经验,但是如果您将一个使用 URL 作为类路径的子类(以便它可以找到类文件)并且父类加载器无法加载它(不是类路径的一部分),将使用您的自定义路径。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多