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

Jetty 10/11使用Custom Logging调用request方法触发NPE问题求解

问题原因
  • 空指针的直接原因:setCustomAttributesToLog 方法是在 JettyCustomLogger 的构造函数中执行的,构造阶段还没有任何请求进入,request 静态变量还没有被赋值,调用 request.getMethod() 必然抛出空指针。你对 request 变量的赋值逻辑写在 log 方法中,这个方法只有实际请求到达时才会被触发,执行时机远晚于构造函数。
  • 额外隐藏问题:把 Request 对象设为静态变量存在严重线程安全风险,Jetty 是多线程处理请求的,多个请求会同时修改这个静态变量,最终日志记录的请求属性会出现错乱,完全不符合业务预期。
  • 设计逻辑错误:你要拼接的请求相关属性每个请求都不一样,不能在日志组件初始化阶段就把日志格式拼死,必须在每次请求处理完成、触发日志记录时动态拼接当前请求的属性。
解决方案

调整实现逻辑,把请求属性的获取、自定义字段的拼接逻辑放到 log 方法中执行,同时去掉静态 request 变量,避免线程安全问题。示例实现代码如下:

import org.eclipse.jetty.server.CustomRequestLog;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import java.io.Writer;
import java.io.IOException;

public class JettyCustomLogger extends CustomRequestLog
{
    // 存储基础日志格式字符串,不要在构造阶段就拼接请求相关内容
    private final String baseLogStr;

    @Override
    public void log(Request request, Response response)
    {
        // 每次请求都动态获取当前请求的属性拼接日志
        String finalLogContent = setCustomAttributesToLog(request, baseLogStr);
        // 可选择直接输出自定义拼接好的日志,不走父类原有格式解析逻辑,更灵活
        try (Writer writer = getWriter()) {
            writer.write(finalLogContent + System.lineSeparator());
        } catch (IOException e) {
            // 自行处理日志写入异常
            e.printStackTrace();
        }
        // 如果需要保留父类原有格式解析能力,也可以调用super.log()实现
        // super.log(request, response);
    }

    public JettyCustomLogger(Writer writer, String logStr)
    {
        super(writer, logStr);
        this.baseLogStr = logStr;
    }

    // 方法增加Request入参,每次调用传入当前请求的对象,不需要用静态变量存储
    private String setCustomAttributesToLog(Request request, String logStr)
    {
        String method = request.getMethod();
        StringBuilder logBuffer = new StringBuilder(logStr);
        logBuffer.append(method);
        // 你自己的其他int、string类型自定义属性拼接逻辑都可以在这里实现
        logBuffer.append(" Ashish");
        logBuffer.append(" ");
        logBuffer.append("Goyanka");
        logBuffer.append(" ");
        logBuffer.append("absgdh");
        logBuffer.append(" ");
        return logBuffer.toString();
    }
}

如果需要保留父类 CustomRequestLog 原有格式解析能力,还可以通过自定义 RequestLog.Writer 或者扩展 Jetty 的日志格式字段实现,上述方案是改动最小、最容易适配你现有自定义属性拼接需求的实现。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 13:15:03