我正在开发一个Web应用程序。
com.people.Customer.java
repository/com/people/Customer.class
,它不在我的应用程序服务器的类路径中。我的应用程序服务器(我使用的是WebSphere) Application Server / Apache Tomcat等)从WEB-INF/classes
目录中获取类。类加载器将使用它来加载类。Thread.currentThread().getContextClassLoader().loadClass(com.people.Customer)
时,显然Classloader无法加载类,因为它不在类路径上(不在WEB-INF/classes
中)。由于类似原因,getResource(..)
或getResourceAsStream(..)
也不起作用。我需要一种方法:
将类Customer.class
作为流(或任何其他方式)读取,然后加载它。以下是限制因素:
WEB-INF/classes
文件夹。有没有办法实现这个目标?
如果不是这样,在更糟糕的情况下,是否有一种方法可以使用Web应用程序的自定义类加载器覆盖默认类加载器,应该使用相同的类加载器在我的Web应用程序的整个生命周期中加载应用程序。
欣赏任何解决方案:)
答案 0 :(得分:2)
您需要一个自定义类加载器才能执行此操作,在此类加载器中,您需要重新定义方法findClass(String name)
一个例子:
public class CustomClassLoader extends ClassLoader {
final String basePath = "/your/base/path/to/directory/named/repository/";
@Override
protected Class<?> findClass(final String name) throws ClassNotFoundException {
String fullName = name.replace('.', '/');
fullName += ".class";
String path = basePath + fullName ;
try {
FileInputStream fis = new FileInputStream(path);
byte[] data = new byte[fis.available()];
fis.read(data);
Class<?> res = defineClass(name, data, 0, data.length);
fis.close();
return res;
} catch(Exception e) {
return super.findClass(name);
}
}
}
然后,您将从自定义位置加载类。例如:
Class<?> clazz = Class.forName("my.pretty.Clazz", true, new CustomClassLoader());
Object obj = clazz.newInstance();
执行此操作,您告诉JVM应该由您的自定义类加载器加载名为my.pretty.Clazz
的类,该加载器知道如何和从哪里来加载您的自定义类。
它将完整的类名称(如my.pretty.Clazz
)解析为文件名(在我们的例子中为/your/base/path/to/directory/named/repository/my/pretty/Clazz.class
),然后将获取的资源作为字节数组加载,最后将此数组转换为Class
实例
此示例非常简单,并演示了如何在您的情况下加载自定义类的一般技术。 我建议你阅读一些关于类加载的文章,例如this one。
答案 1 :(得分:1)
简短回答:否
如果没有自定义ClassLoader,则无法动态加载类。
但是,您假设您不能使用自定义ClassLoader,因为WebApp ClassLoader加载的其他对象无法使用这些新加载的类是不正确的。您只需要使用这些新创建的类的通用方法 - 比如通用接口或元描述(Beans Introspector用于访问bean属性)。
但是如果你正在使用像Hibernate这样的第三方库,并且你在运行时动态加载要保留的实体,那么你将会遇到困难,但是有可能这样做。
答案 2 :(得分:1)
当然可以这样做。只需获取web类加载器并使用反射调用defineClass()方法(它受到保护,所以一定要在方法上调用setAccessible(true).defineClass()接受一个字节数组,所以它对你没有任何区别class来自。确保类名是唯一的,你只加载一次,否则你会遇到复杂的类加载问题。