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

使用Java Agent+Javassist增强Spring应用时找不到HttpServletRequest接口

问题:Java Agent结合Javassist修改DispatcherServlet时找不到HttpServletRequest类

我使用Java Agent结合Javassist为Spring应用添加插桩代码,尝试在DispatcherServlet的doDispatch()方法前后插入System.out输出语句,却遇到异常:

javassist.CannotCompileException: cannot find javax.servlet.http.HttpServletRequest

javax.servlet.http.HttpServletRequest是DispatcherServlet已导入的接口类,推测是类加载顺序导致的问题。我尝试通过pool.appendClassPath("javax/servlet/http")添加类路径,但并未解决问题。我的Transformer代码如下:

public byte[] transform(ClassLoader loader, String className,
                        Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
                        byte[] classfileBuffer) throws IllegalClassFormatException {
    boolean changed = false;
    if (className.equals("org/springframework/web/servlet/DispatcherServlet")) {
        try {
            String name = className.replaceAll("/", ".");
            pool.insertClassPath(new ByteArrayClassPath(name, classfileBuffer));
            CtClass cclass = pool.get(name);

            for (CtMethod currentMethod: cclass.getDeclaredMethods("doDispatch")) {
                try {
                    currentMethod.insertBefore("System.out.println(\"before handler\");");
                    currentMethod.insertAfter("System.out.println(\"after handler\");");
                    changed = true;
                } catch(javassist.CannotCompileException e) {
                    logger.error(e + ": " + currentMethod);
                }
            }
            if (changed) {
                classfileBuffer = cclass.toBytecode();
                cclass.detach();
                return classfileBuffer;
            }
            cclass.detach();
        } catch(NotFoundException e) {
            logger.error(e + ": " + className);
        } catch (Exception e) {
            logger.error(e + ": " + className);
        }
    }

    return null; // didn't change anything
}

解决方案
  • 关联目标类的类加载器到Javassist的ClassPool
    Javassist默认使用自身的类加载器,而DispatcherServlet和HttpServletRequest是由应用类加载器加载的。需要将目标类的ClassLoader添加到ClassPool的类路径中:

    // 在插入ByteArrayClassPath之后添加这行
    pool.insertClassPath(new LoaderClassPath(loader));
    

    这样Javassist就能通过应用类加载器正确找到HttpServletRequest类。

  • 移除无效的类路径添加代码
    之前使用的pool.appendClassPath("javax/servlet/http")是错误用法,该方法需要传入JAR文件路径或目录路径,而非类的包路径,直接删除这行代码即可。

  • 应急方案:使用全限定类名(非必要)
    如果类加载器关联后仍有问题(尽管你的插桩代码本身没用到HttpServletRequest),可以在涉及该类的代码中使用全限定类名,例如:javax.servlet.http.HttpServletRequest request = ...。但核心解决方式还是类加载器的关联。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 23:22:56