[英]How to use Custom ClassLoader to new Object in Java
我想创建一个自定义的ClassLoader来加载某个路径(例如/ home / custom / lib)中的所有jar文件。
那么我希望每次使用new
运算符创建一个Object时,它将在该路径中的所有jar文件中搜索类,然后搜索由参数( -cp
)定义的类路径。
可能吗?
例如,在/home/custom/lib/a.jar
有一个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();
}
}
类加载器无法完全完成您期望的操作。
引用相关问答的另一个答案 :
Java将始终使用加载了正在执行的代码的类加载器。
因此,以您的示例为例:
public static void main(String[] args) {
// whatever you do here...
Car car = new Car(); // ← this code is already bound to system class loader
}
你可以得到最接近的将是使用儿童第一(父最后一)类加载器 ,如这一个 ,你的罐子实例化,然后使用反射来创建的实例Car
从罐子。
a.jar
Car
类别:
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
类,则该类不是同一类,因为一个类由其全名和类加载器标识。
为了说明这一点,假设我使用了下面的本地Car
类,并通过自定义类加载器按上面的carClass
加载了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
则位于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容器所做的事情:
javax.servlet.Servlet
的类) web.xml
文件)告诉servlet容器它需要实例化的servlet(类)的名称(就像我们上面所做的一样) Servlet
,则Servlet容器可以这样使用它们 在您的情况下,您不需要编写新的ClassLoader,因为您唯一想做的就是在运行时扩展类路径。 为此,您将获得当前的SystemClassLoader实例,并使用URLClassLoader向其添加classpath条目。
车类已 编译并位于 C:\\ Users \\ xxxx \\ Documents \\ sources \\ test \\ target \\ classes中
public class Car {
public String prout() {
return "Test test!";
}
}
主班
public static void main(String args[]) throws Exception {
addPath("C:\\Users\\xxxx\\Documents\\sources\\test\\target\\classes");
Class clazz = ClassLoader.getSystemClassLoader().loadClass("Car");
Object car = clazz.newInstance();
System.out.println(clazz.getMethod("prout").invoke(car));
}
public static void addPath(String s) throws Exception {
File f=new File(s);
URL u=f.toURI().toURL();
URLClassLoader urlClassLoader=(URLClassLoader)ClassLoader.getSystemClassLoader();
Class urlClass=URLClassLoader.class;
Method method=urlClass.getDeclaredMethod("addURL",new Class[]{URL.class});
method.setAccessible(true);
method.invoke(urlClassLoader,new Object[]{u});
}
ClassLoader.getSystemClassLoader().loadClass(String name)
从中加载类。先前添加的类路径条目。 如果不需要该类路径条目供以后使用,则可以实例化自己的URLClassLoader
实例并相应地加载类,而不是在SystemClassLoader上设置类路径条目。 即:
public static void main(String[] args) {
try {
File file = new File("c:\\other_classes\\");
//convert the file to URL format
URL url = file.toURI().toURL();
URL[] urls = new URL[]{ url };
//load this folder into Class loader
ClassLoader cl = new URLClassLoader(urls);
//load the Address class in 'c:\\other_classes\\'
Class cls = cl.loadClass("com.mkyong.io.Address");
} catch (Exception ex) {
ex.printStackTrace();
}
}
来源: https : //www.mkyong.com/java/how-to-load-classes-which-are-not-in-your-classpath/
问:我想创建一个自定义的ClassLoader来加载某个路径(例如/ home / custom / lib)中的所有jar文件。
那么我希望每次使用new运算符创建一个Object时,它都会在该路径中所有jar文件中搜索类,然后搜索由参数(-cp)定义的类路径。
可能吗?
如果希望能够使用new
关键字,则需要修改编译器javac -classpath path
的类javac -classpath path
否则在编译时它将不知道从何处加载类。
编译器正在加载用于类型检查的类。 (此处的更多信息: http : //docs.oracle.com/javase/7/docs/technotes/tools/windows/javac.html#searching )
这是不可能使用new
的关键字通过在运行一个定制的ClassLoader加载的类由于编译器内部实现new
关键字。
编译器和JVM(运行时)都有自己的ClassLoader,您无法自定义javac classloader,据我所知,唯一可以从编译器中自定义的部分是注释处理。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.