如何在Java中使用自定义类加载器来新建对象

2024-05-31

我想创建一个自定义类加载器来加载某个路径(例如/home/custom/lib)中的所有jar文件。

然后我希望每次我使用new运算符创建一个Object,它会在该路径下的所有jar文件中搜索class,然后搜索参数定义的类路径(-cp).

是否可以?

例如,有一个jar文件/home/custom/lib/a.jar

在主班

public class Main {
    public static void main(String[] args) {
        // do something here to use custom ClassLoader
        // here will search Car in /home/custom/lib/a.jar first then in java class path
        Car car = new Car(); 
    }
}

类加载器不能完全按照您的预期执行。

Quoting 另一个答案 https://stackoverflow.com/a/10192692/6730571相关问答:

Java 将始终使用加载正在执行的代码的类加载器。

以你的例子为例:

public static void main(String[] args) {
    // whatever you do here...
    Car car = new Car(); // ← this code is already bound to system class loader
}

你能得到的最接近的结果是使用子优先(父最后)类加载器例如this one https://stackoverflow.com/a/5446671/6730571,用你的 jar 实例化它,然后使用反射创建一个实例Car从那个罐子里。

Car类内a.jar:

package com.acme;
public class Car {
    public String honk() {
        return "Honk honk!";
    }
}

您的主要应用:

public static void main(String[] args) throws MalformedURLException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
    ParentLastURLClassLoader classLoader = new ParentLastURLClassLoader(
            Arrays.asList(new File("/home/lib/custom/a.jar").toURI().toURL()));
    Class<?> carClass = classLoader.loadClass("com.acme.Car");
    Object someCar = carClass.newInstance();
    Object result = carClass.getMethod("honk").invoke(someCar);
    System.out.println(result); // Honk honk!
}

需要注意的是:如果您也有com.acme.Car类路径中的 .class ,这不是同一个类,因为类是通过其全名和类加载器来标识的。

为了说明这一点,假设我使用了本地Car类如下carClass由我的自定义类加载器按上述方式加载:

Car someCar = (Car) carClass.newInstance();
// java.lang.ClassCastException: com.acme.Car cannot be cast to com.acme.Car

可能会令人困惑,但这是因为名称本身并不能识别类。该转换无效,因为这两个类不同。它们可能具有不同的成员,或者它们可能具有相同的成员但不同的实现,或者它们可能是逐字节相同的:它们不是同一个类。

现在,这并不是一件很有用的事情。
这样的事情就变成了当 jar 中的自定义类实现通用 API(主程序知道如何使用)时很有用.

例如,假设接口Vehicle(其中有方法String honk()) 位于公共类路径中,并且您的Car is in a.jar并实施Vehicle.

ParentLastURLClassLoader classLoader = new ParentLastURLClassLoader(
        Arrays.asList(new File("/home/lib/custom/a.jar").toURI().toURL()));
Class<?> carClass = classLoader.loadClass("com.acme.Car");
Vehicle someCar = (Vehicle) carClass.newInstance(); // Now more useful
String result = someCar.honk(); // can use methods as normal
System.out.println(result); // Honk honk!

这与 servlet 容器的作用类似:

  • 您的应用程序实现了 servlet API(例如,实现了javax.servlet.Servlet)
  • 它被打包成一个 war 文件,servlet 容器可以使用自定义类加载器加载该文件
  • 部署描述符(web.xml文件)告诉 servlet 容器它需要实例化的 servlet(类)的名称(如我们上面所做的那样)
  • 这些课程是Servlets,servlet 容器可以这样使用它们
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在Java中使用自定义类加载器来新建对象 的相关文章

随机推荐