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

Quarkus:拦截器注入请求作用域Bean触发ContextNotActiveException问题排查

问题描述

我开发了一个Quarkus应用,入口为实现AWS RequestHandler的类。在执行业务逻辑前,希望根据传入参数设置上下文,因此创建了标注@RequestScoped的Bean用于存储上下文,通过setter方法赋值。

尝试使用拦截器实现该逻辑,在拦截器类中注入这个请求作用域Bean,但运行应用时拦截器触发后调试报错:

Method threw 'javax.enterprise.context.ContextNotActiveException'. Cannot evaluate common.service.MyRequestScopedBean_ClientProxy.toString()

另一个以REST接口为入口的Quarkus应用执行相同逻辑则无问题,当前使用Quarkus版本为2.7.5.Final。

相关代码如下:

上下文Bean

@Setter
@Getter
@RequestScoped
public class MyRequestScopedBean {

    private String context;
}

拦截器绑定注解

@InterceptorBinding
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ContextBinding {
}

拦截器类

@Slf4j
@Interceptor
@ContextBinding
public class ContextInterceptor {

    @Inject
    MyRequestScopedBean myRequestScopedBean;

    @AroundInvoke
    public Object setContext(InvocationContext context) throws Exception {

        log.info("{}", context);

        myRequestScopedBean.setContext("Some context");

        return context.proceed();
    }
}

Handler类

@Slf4j
@ActivateRequestContext
@ContextBinding
@Named("Handler")
public class Handler implements RequestHandler<Event, Void> {

    @Override
    public Void handleRequest(Event event, Context context) {
        // some logic
    }
}
原因分析

Quarkus中,@ActivateRequestContext的生效时机是目标方法(即handleRequest)执行时才会激活请求上下文,但拦截器的@AroundInvoke方法会在目标方法执行前触发——此时请求上下文尚未激活,注入的@RequestScoped Bean无法获取到活跃的上下文,因此抛出ContextNotActiveException。

而REST接口场景下,Quarkus会在请求进入时自动激活请求上下文,拦截器执行时上下文已经存在,所以不会出现该错误。

解决方法

方法1:手动在拦截器中激活请求上下文

通过RequestContextController手动控制请求上下文的激活与关闭,确保操作@RequestScoped Bean时上下文处于活跃状态:

@Slf4j
@Interceptor
@ContextBinding
public class ContextInterceptor {

    @Inject
    MyRequestScopedBean myRequestScopedBean;
    
    @Inject
    RequestContextController requestContextController;

    @AroundInvoke
    public Object setContext(InvocationContext context) throws Exception {
        // 手动激活请求上下文
        requestContextController.activate();
        try {
            log.info("{}", context);
            myRequestScopedBean.setContext("Some context");
            return context.proceed();
        } finally {
            // 确保请求上下文最终被关闭
            requestContextController.deactivate();
        }
    }
}

方法2:将@ActivateRequestContext移至拦截器类

移除Handler类上的@ActivateRequestContext,将其标注在拦截器类上,让请求上下文在拦截器执行前就被激活(Quarkus 2.7.5.Final支持此用法):

@Slf4j
@Interceptor
@ContextBinding
@ActivateRequestContext
public class ContextInterceptor {
    // 保持原有拦截器逻辑不变
}

方法3:调整上下文设置逻辑的触发时机

如果业务允许,可以将上下文设置逻辑直接放在handleRequest方法的开头,此时@ActivateRequestContext已经激活了请求上下文,注入的@RequestScoped Bean可以正常使用:

@Slf4j
@ActivateRequestContext
@Named("Handler")
public class Handler implements RequestHandler<Event, Void> {

    @Inject
    MyRequestScopedBean myRequestScopedBean;

    @Override
    public Void handleRequest(Event event, Context context) {
        // 直接在方法内设置上下文
        myRequestScopedBean.setContext("Some context");
        // some logic
    }
}

这种方式可以省去拦截器的使用,适合逻辑简单的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 10:33:25