【问题标题】:Java EE application custom compiling classloaderJava EE 应用程序自定义编译类加载器
【发布时间】:2011-12-07 18:18:50
【问题描述】:

以下是要求:

  1. Java EE Web 应用程序(在 Tomcat 中)...
  2. 非常简单,只有 JSP、servlet 和 jar - 没有框架...
  3. 无需重新加载,无需重新加载服务器,无需上下文,无需重新加载...

到目前为止,我们的想法是扩展 WebappClassLoader (catalina.jar) 以制作您自己的自定义类加载器,并将其作为 Loader 元素在 context.xml 中注册。用一些代码你可以很好地编写你的类加载器,谁会知道在哪里可以找到 java 源文件,然后在需要时将它们编译成类文件,然后在被要求时将它们加载到内存中。逻辑简单明了。

除了:

Jasper 将如何知道在哪里 - 自动 - 找到您的自定义类加载器生成的类,以便它可以编译引用它们的 JSP,甚至动态刷新它们(您的类)?是不可能实现的吗?

你怎么看?

(请不要试图通过指向许多确实为您处理此类事情的现有框架来分散对话。要求非常具体:没有框架,什么都没有)

【问题讨论】:

  • Jasper 的文档规定:“JDT 用于编译 JSP 页面 - Eclipse JDT Java 编译器现在用于执行 JSP java 源代码编译。此编译器从容器类加载器。Ant 和 javac 仍然可以使用。”。所以这个问题实际上是关于 "container classloader"!
  • 容器类加载器是“org.apache.catalina.loader.StandardClassLoader”的一个实例。它是 Engine 的 类加载器。我没有看到任何明显的方法来覆盖/补充它以自动工作......

标签: jsp servlets classloader web-applications


【解决方案1】:

可以在当前 Web 应用程序上下文 (context.xml) 中添加类加载器:

<Context>
    <Loader loaderClass = "gr.nevma.cccl.CompilingClassLoader"/>
</Context>

然后创建一个类加载器,如:

package package gr.nevma.cccl;

import ...

public class CompilingClassLoader extends WebappClassLoader {

    public CompilingClassLoader ( ClassLoader parentClassLoader ) {

        super( parentClassLoader );

    }

    public Class<?> loadClass ( String className, boolean resolve ) throws ClassNotFoundException { 

        Class<?> theClass = null;

        // Do you stuff here
        return theClass;

    }

}

但这只有在希望能够通过调用 ClassLoader::loadClass(...) 从类加载器本身显式加载类时才有帮助。这对 Jasper 的 JSP 编译没有帮助。这意味着当 Jasper 将尝试编译使用将由该类加载器加载的类的 JSP 时,编译将失败,因为 Jasper 甚至根本不会要求该类加载器加载任何类。

因此,通过这种方式,可以实现类的自动加载和重新加载,但需要以一种手动方式。这些类可以在整个 Web 应用程序(即 JSP 页面)中统一使用!

【讨论】:

  • 好像调用了WebappClassLoader的getResourceAsStream()方法来加载Jasper编译JSP页面需要的类。换句话说,当 Jasper 试图编译 JSP 页面时,它通过调用 getResourceAsStream() 从类加载器请求必要的类。所以需要重写这个方法来动态加载任何需要加载的东西...
  • 为了能够加载然后重新加载任何类(即“定义”它),必须删除并重新创建它的类加载器。换句话说,类加载器的实例只能加载(定义)一个类一次!如果需要实际重新加载(再次定义)类,则必须为此作业创建一个新的类加载器,并删除旧的类加载器。
  • 当一个类加载器加载了一个类一次,JVM 似乎再也不会向它请求这个类,至少只要 PermGen 内存(类存储在 RAM 中)是不满。因此,这使得类加载器不可避免地被删除并重新创建,以便能够重新加载类的定义。这更清楚地表明,如果重新加载的类的引用仍然悬而未决,那么加载它们的类加载器的实例将不会被垃圾回收。
  • 另外,通过查看Tomcat的源代码,在Jasper的JspCompilationContext类中,可以看出这正是Jasper为了编译和重新加载JSP页面所做的!它定期检查 JSP 源文件是否有更改,如果发现任何更改,它会销毁其类加载器,创建它的新实例,编译需要编译的 JSP 页面并使用新的类加载器实例重新加载它们。而且,是的,这听起来确实是服务器要做的“大量工作”,如果它以非常频繁的速度设置的话。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-14
  • 1970-01-01
  • 2011-03-30
  • 1970-01-01
  • 2023-02-03
相关资源
最近更新 更多