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();
}
}
我想创建一个自定义ClassLoader来加载某些路径中的所有jar文件(例如/ home / custom / lib)。
然后我希望每次使用new
运算符创建一个Object时,它将在该路径中的所有jar文件中搜索类,然后搜索由参数(-cp
)定义的类路径。
有可能吗?
例如,/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();
}
}
答案 0 :(得分:5)
类加载器无法完全按照您的预期执行。
引用相关Q& A的another answer:
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,将它与你的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
类,那就不是同一个类,因为一个类是由它的全名和类加载器标识的。
为了说明这一点,假设我使用了我的本地Car
类,如下所示,我的自定义类加载器加载了carClass
:
Car someCar = (Car) carClass.newInstance();
// java.lang.ClassCastException: com.acme.Car cannot be cast to com.acme.Car
可能会让人感到困惑,但这只是因为这个名字并不能识别这个类。该演员表无效,因为2个班级不同。它们可能有不同的成员,或者它们可能具有相同的成员但实现不同,或者它们可能是逐字节相同的:它们不是同一个类。
现在,这不是一件非常有用的事情 当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容器可以这样使用它们答案 1 :(得分:0)
在您的情况下,您不需要编写新的ClassLoader,因为您唯一要做的就是在运行时扩展类路径。 为此,您将获得当前的SystemClassLoader实例,并使用 URLClassLoader 将类路径条目添加到其中。
Car class 已编译并位于 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来加载所有jar文件 在某些路径中(例如/ home / custom / lib)。
然后我希望每次使用new运算符创建一个Object时 它将在该路径中的所有jar文件中搜索类,然后搜索 由参数(-cp)定义的类路径。
有可能吗?
如果您希望能够使用new
关键字,则需要修改编译器javac -classpath path
的类路径
否则在编译时它不知道从哪里加载类。
编译器正在加载类以进行类型检查。 (此处有更多信息:http://docs.oracle.com/javase/7/docs/technotes/tools/windows/javac.html#searching)
由于编译器内部实现了new
关键字,因此无法在运行时对自定义ClassLoader加载的类使用new
关键字。
编译器和JVM(运行时)有自己的ClassLoaders,你不能自定义javac类加载器,据我所知,唯一可以从编译器自定义的部分是注释处理。