You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

嵌入式Jetty Web应用部署中的类加载器问题

解决跨类加载器的ClassCastException问题

嘿,这个坑我踩过好多次了!核心原因其实很简单:JVM判定两个类是否为同一个类型,不仅看全限定类名,还要看加载它们的类加载器是否相同。你遇到的两种情况,本质都是系统类加载器(main方法用的)和Web应用类加载器(Servlet用的)各自加载了SomeClass,导致两个类型看似相同实则完全不兼容。

为什么会抛出ClassCastException?

当你在main方法里用系统类加载器实例化SomeClass,并把它放进Servlet上下文后,Servlet里的代码会尝试用Web应用类加载器去加载SomeClass来做类型转换。这时候JVM会认为:“这两个SomeClass来自不同的类加载器,是完全不同的类型”,直接抛出ClassCastException——哪怕它们的代码一模一样。

用WebAppContext.addSystemClasses怎么解决?

WebAppContext.addSystemClasses这个方法的作用,就是告诉Web应用类加载器:遇到指定的类时,不要自己加载,委托给系统类加载器去加载。这样一来,Servlet里拿到的SomeClass类型,和main方法里实例化的对象所属的类型,就来自同一个类加载器了,强转自然就没问题。

具体操作步骤

  1. 配置类加载委托规则:在启动Web容器(比如Jetty,因为WebAppContext是Jetty的核心类)的时候,添加如下代码:
    WebAppContext webAppContext = new WebAppContext();
    // 让Web应用类加载器委托系统类加载器加载SomeClass
    webAppContext.addSystemClasses(SomeClass.class.getName());
    // 如果SomeClass还有依赖的其他类,也要一起加进来,比如:
    // webAppContext.addSystemClasses(SomeDependency.class.getName());
    
  2. 确保类的存放位置正确:一定要把SomeClass的字节码放在系统类加载器能加载到的路径下(比如JVM的classpath),绝对不能放在Web应用的WEB-INF/classes或者WEB-INF/lib里——不然Web应用类加载器会优先加载自己路径下的类,忽略你设置的委托规则,问题还会重现。

代码示例

  • main方法里放入上下文:
    public static void main(String[] args) throws Exception {
        Server server = new Server(8080);
        WebAppContext webAppContext = new WebAppContext();
        webAppContext.addSystemClasses(SomeClass.class.getName());
        server.setHandler(webAppContext);
    
        // 实例化对象(系统类加载器加载)
        SomeClass obj = new SomeClass();
        // 放入Servlet上下文
        webAppContext.setAttribute("myObj", obj);
    
        server.start();
        server.join();
    }
    
  • Servlet里获取并使用:
    @WebServlet("/test")
    public class TestServlet extends HttpServlet {
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // 这里拿到的SomeClass是系统类加载器加载的,和main里的对象类型一致
            SomeClass obj = (SomeClass) getServletContext().getAttribute("myObj");
            // 正常使用obj
        }
    }
    

额外注意事项

  • 如果SomeClass有继承或实现的接口,也要确保接口被同一个类加载器加载——要么一起添加到addSystemClasses,要么也放在系统类路径下。
  • 不要滥用addSystemClasses,只添加确实需要跨类加载器共享的类,不然可能导致Web应用之间的类隔离失效,引发其他问题。

内容的提问来源于stack exchange,提问作者Ben

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:13:34