Java 在web应用程序中动态加载不在类路径中的类-不使用自定义类加载器
我正在开发一个web应用程序Java 在web应用程序中动态加载不在类路径中的类-不使用自定义类加载器,java,classloader,Java,Classloader,我正在开发一个web应用程序 web应用程序动态生成java类。例如,它生成类com.people.Customer.java 在我的代码中,我动态编译它以获取com.people.Customer.class并存储在某个目录中,比如repository/com/people/Customer.class,它不在我的应用服务器的类路径上。我的应用服务器(我使用的是WebSphere application server/Apache Tomcat等)从WEB-INF/classes目录中拾取类。
com.people.Customer.java
repository/com/people/Customer.class
,它不在我的应用服务器的类路径上。我的应用服务器(我使用的是WebSphere application server/Apache Tomcat等)从WEB-INF/classes
目录中拾取类。类加载器将使用它来加载类Thread.currentThread().getContextClassLoader().loadClass(com.people.Customer)
时,显然类加载器无法加载该类,因为它不在类路径上(不在WEB-INF/classes
)。由于类似的原因,getResource(..)
或getResourceAsStream(..)
也不起作用Customer.class
可能作为流(或任何其他方式)并加载它。以下是限制条件:
WEB-INF/classes
文件夹感谢任何解决方案:)简短回答:否 如果没有自定义类加载器,则无法动态加载类 但是,由于WebApp类加载器加载的其他对象将无法使用这些新加载的类,因此您不能使用自定义类加载器的假设是不正确的。您所需要的只是使用这些新创建的类的通用方法——比如公共接口或元描述(用于访问bean属性的bean内省器)
但是,如果您使用的是第三方库,如Hibernate,并且您在运行时动态加载要持久化的实体,那么您将有一段困难的时间,但我认为这是可能的。确实可以做到这一点。只需获取web类加载器并使用反射调用defineClass()方法(它受保护,因此请确保对该方法调用setAccessible(true)。defineClass()获取一个字节数组,因此它与类的来源没有任何区别。请确保类名是唯一的,并且只加载一次,否则您将遇到复杂的类加载问题。您需要一个自定义类加载程序来执行此操作,并且在此类加载程序中,您需要重新定义一个方法
findClass(字符串名称)
例如:
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);
}
}
}
公共类CustomClassLoader扩展了ClassLoader{
最终字符串basePath=“/your/base/path/to/directory/named/repository/”;
@凌驾
受保护类findClass(最终字符串名称)引发ClassNotFoundException{
字符串fullName=name.replace('.','/');
全名+=“.class”;
字符串路径=基本路径+全名;
试一试{
FileInputStream fis=新的FileInputStream(路径);
字节[]数据=新字节[fis.available()];
fis.读取(数据);
Class res=defineClass(名称,数据,0,数据长度);
fis.close();
返回res;
}捕获(例外e){
返回super.findClass(名称);
}
}
}
然后,您将从自定义位置加载类。例如:
Class<?> clazz = Class.forName("my.pretty.Clazz", true, new CustomClassLoader());
Object obj = clazz.newInstance();
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
实例
这个示例非常简单,并演示了一种有关如何像您的案例那样加载自定义类的通用技术。
例如,我建议您阅读一些关于类加载的文章。为什么不能将其添加到WEB-INF/classes文件夹中?这是真正的解决方案。在任何情况下都是“不能”还是“不会”或“宁愿不”?@duffymo:你的假设是webapp是在扩展模式下部署的,并且webapp对文件系统具有写入权限。在生产环境中并不总是这样。将文件写入WEB-INF/类不是一个好的解决方案不,我没有任何这样的假设-你的透视界面已关闭,mhaller。我认为e-WAR应该重新打包以包含所有必需的.class文件并重新部署。我希望看到这样一个用例,即有必要创建一些像Customer on the fly这样显而易见的东西。实例?是的。类?不,我不买。嗯,我知道这个用例,因为我们正在这样做。我们的客户部署新的生成代码在运行时,独立于运行此代码的web应用程序。可以说是appserver中的appserver。这就是为什么我理解swdeveloper的请求,尽管我必须承认这是不寻常的,当然我不会在“正常”web应用程序中使用类似的内容。类“Customer”如果您认为“静态”域模型可能不是一个合适的例子