在Web应用程序中动态加载类不在类路径中 - 不使用自定义类加载器

时间:2010-03-18 22:04:39

标签: java classloader

我正在开发一个Web应用程序。

  1. Web应用程序动态生成java类。例如,它会生成类com.people.Customer.java
  2. 在我的代码中,我动态编译它以获取com.people.Customer.class并存储在某个目录中,说repository/com/people/Customer.class,它不在我的应用程序服务器的类路径中。我的应用程序服务器(我使用的是WebSphere) Application Server / Apache Tomcat等)从WEB-INF/classes目录中获取类。类加载器将使用它来加载类。
  3. 编译后我需要加载这个类,以便在创建它之后使用它可以访问它。
  4. 当我使用Thread.currentThread().getContextClassLoader().loadClass(com.people.Customer)时,显然Classloader无法加载类,因为它不在类路径上(不在WEB-INF/classes中)。由于类似原因,getResource(..)getResourceAsStream(..)也不起作用。
  5. 我需要一种方法:

    将类Customer.class作为流(或任何其他方式)读取,然后加载它。以下是限制因素:

    1. 我无法将存储库文件夹添加到WEB-INF/classes文件夹。
    2. 我无法创建新的Custom ClassLoader。如果我创建一个新的ClassLoader并加载该类,则其父类ClassLoader将无法访问它。
    3. 有没有办法实现这个目标?

      如果不是这样,在更糟糕的情况下,是否有一种方法可以使用Web应用程序的自定义类加载器覆盖默认类加载器,应该使用相同的类加载器在我的Web应用程序的整个生命周期中加载应用程序。

      欣赏任何解决方案:)

3 个答案:

答案 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来自。确保类名是唯一的,你只加载一次,否则你会遇到复杂的类加载问题。

相关问题