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

如何在Spring异常处理器中访问请求作用域的Bean?

解决请求作用域Bean无法注入到异常处理器的问题

核心问题:Spring的@ExceptionHandler方法默认不支持直接注入请求作用域的Bean,因为异常处理阶段的参数解析逻辑不包含自定义请求作用域Bean的解析,导致报错No suitable resolver。

以下是几种可行的解决方案:

方案一:通过RequestContextHolder获取请求上下文绑定的Bean

将请求作用域的Tracer Bean定义移到配置类,并开启代理模式,确保Bean能在请求上下文外被间接访问;然后在异常处理器中通过RequestContextHolder获取当前请求的上下文,进而拿到Tracer实例。

步骤1:调整Tracer的Bean定义

创建配置类,定义请求作用域的Tracer Bean并指定代理模式:

@Configuration
public class TraceConfig {
    @Bean
    @RequestScope(proxyMode = ScopedProxyMode.TARGET_CLASS)
    public Tracer tracer() {
        return new Tracer();
    }
}

步骤2:修改异常处理器方法

@ExceptionHandler({Exception.class})
ResponseEntity<String> defaultExceptionHandler(HttpServletRequest req, Exception ex) {
    ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
    if (attributes != null) {
        // 请求作用域Bean会以"scopedTarget.xxx"为key存入request属性
        Tracer tracer = (Tracer) attributes.getRequest().getAttribute("scopedTarget.tracer");
        return ResponseEntity
                .internalServerError()
                .body("ERROR: " + tracer.getCorrelationId());
    }
    return ResponseEntity.internalServerError().body("ERROR: No trace info available");
}

方案二:将Tracer实例存入HttpServletRequest属性

在控制器方法中,先获取Tracer实例并存入当前请求的属性中,异常处理器直接从HttpServletRequest中取出该实例。

修改控制器和异常处理器代码

@GetMapping(path = "throw")
public String throwEx(Tracer trace, HttpServletRequest req){
    // 将Tracer存入请求属性
    req.setAttribute("currentTracer", trace);
    throw new RuntimeException("Ops");
}

@ExceptionHandler({Exception.class})
ResponseEntity<String> defaultExceptionHandler(HttpServletRequest req, Exception ex) {
    // 从请求属性中取出Tracer
    Tracer tracer = (Tracer) req.getAttribute("currentTracer");
    return ResponseEntity
            .internalServerError()
            .body("ERROR: " + tracer.getCorrelationId());
}

方案三:使用ObjectFactory延迟获取请求作用域Bean

通过注入ObjectFactory<Tracer>来延迟获取Bean实例,ObjectFactory会确保在请求上下文存在的时机获取到当前请求绑定的Tracer。

修改控制器代码

@RestController
public class MyController {

    private final ObjectFactory<Tracer> tracerFactory;

    // 构造注入ObjectFactory
    public MyController(ObjectFactory<Tracer> tracerFactory) {
        this.tracerFactory = tracerFactory;
    }

    @GetMapping(path = "throw")
    public String throwEx(Tracer trace){
        throw new RuntimeException("Ops");
    }

    @ExceptionHandler({Exception.class})
    ResponseEntity<String> defaultExceptionHandler(Exception ex) {
        // 延迟获取请求作用域的Tracer实例
        Tracer tracer = tracerFactory.getObject();
        return ResponseEntity
                .internalServerError()
                .body("ERROR: " + tracer.getCorrelationId());
    }
}

注意:此方案同样需要将Tracer的Bean定义移到配置类并开启proxyMode = ScopedProxyMode.TARGET_CLASS。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 23:43:19