如何在Java中使用Custom ClassLoader新建对象 [英] How to use Custom ClassLoader to new Object in Java

查看:74
本文介绍了如何在Java中使用Custom ClassLoader新建对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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



有可能吗?



例如,有一个罐子文件位于 /home/custom/lib/a.jar



主类中

  public class Main {
public static void main(String [] args){
//在此处使用自定义ClassLoader
// //首先在/home/custom/lib/a.jar中搜索Car,然后在Java类路径中搜索
Car car = new Car();
}
}


解决方案

A类加载器无法完全满足您的期望。



引用另一个答案相关问题和解答:


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


因此,您的示例为:

  public static void main(String [] args){
//在这里做什么...
Car car = new Car(); //←此代码已绑定到系统类加载器
}

您能找到的最近的代码得到的将是使用 child-first(父-后)类加载器,例如这一个,使用您的jar实例化它,然后使用反射从该jar中创建 Car 的实例。



< a.jar 中的code> Car 类:

  package com.acme; 
公共类Car {
public String honk(){
返回鸣喇叭!;
}
}

您的主要应用程序:

  public static void main(String [] args)抛出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();
对象结果= carClass.getMethod( honk)。invoke(someCar);
System.out.println(result); //鸣喇叭!
}

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



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

  Car someCar =(Car)carClass.newInstance(); 
// java.lang.ClassCastException:com.acme.Car无法转换为com.acme.Car

可能会引起混淆,但这是因为仅名称不能识别类。该转换无效,因为这两个类不同。它们可能具有不同的成员,或者它们可能具有相同的成员,但实现方式不同,或者它们可能是字节对字节相同的:它们不是同一类。



现在,这不是一件非常有用的事情。

当jar中的自定义类实现通用API(主程序知道如何使用)时,这些事情变得很有用。 / p>

例如,假设接口 Vehicle (其方法为 String honk())在公共类路径中,而您的 Car a.jar 中,并实现车辆

  ParentLastURLClassLoader classLoader = new ParentLastURLClassLoader(
Arrays.asList (新File( / home / lib / custom / a.jar)。toURI()。toURL()));
Class<?> carClass = classLoader.loadClass( com.acme.Car);
Vehicle someCar =(Vehicle)carClass.newInstance(); //现在更有用的
String result = someCar.honk(); //可以使用正常的方法
System.out.println(result); //鸣喇叭!

这类似于servlet容器所做的事情:




  • 您的应用程序实现Servlet API(例如,实现 javax.servlet.Servlet 的类)

  • 打包到war文件中,以便servlet容器可以使用自定义类加载器加载。

  • 部署描述符( web.xml 文件)告诉servlet容器它需要实例化的servlet(类)的名称(就像我们上面所做的一样)

  • 这些类是 Servlet s,servlet容器可以这样使用它们


I want to create a custom ClassLoader to load all jar files in some path(e.g. /home/custom/lib).

then I expect that every time I use new operator to create a Object, it will search class in all jar files in that path, then search the class path defined by parameter (-cp).

Is it possible?

for Example, there is a jar file in /home/custom/lib/a.jar

in Main Class

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

解决方案

A class loader cannot do exactly what you seem to expect.

Quoting another answer of a relevant Q&A:

Java will always use the classloader that loaded the code that is executing.

So with your example:

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

The closest you can get would be to use a child-first (parent-last) class loader such as this one, instanciate it with your jar, then use reflection to create an instance of Car from that jar.

Car class within a.jar:

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

Your main application:

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!
}

To note: if you also have a com.acme.Car class in your class path, that's not the same class, because a class is identified by its full name and class loader.

To illustrate this, imagine I'd used my local Car class as below with the carClass loaded as above by my custom class loader:

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

Might be confusing, but this is because the name alone does not identify the class. That cast is invalid because the 2 classes are different. They might have different members, or they might have same members but different implementations, or they might be byte-for-byte identical: they are not the same class.

Now, that's not a very useful thing to have.
Such things become useful when the custom classes in your jar implement a common API, that the main program knows how to use.

For example, let's say interface Vehicle (which has method String honk()) is in common class path, and your Car is in a.jar and implements 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!

That's similar to what servlet containers do:

  • your application implements the servlet API (e.g. a class that implements javax.servlet.Servlet)
  • it is packaged into a war file, that the servlet container can load with a custom class loader
  • the deployment descriptor (web.xml file) tells the servlet container the names of the servlets (classes) that it needs to instanciate (as we did above)
  • those classes being Servlets, the servlet container can use them as such

这篇关于如何在Java中使用Custom ClassLoader新建对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆