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

字段标注@RequestScoped的工作机制及构造注入场景疑问

关于JAX-RS中CDI作用域标注的问题解答

先来看你提供的代码示例:

JAX-RS资源类

@Path("hello")
public class HelloResource {
    @Inject @RequestScoped FirstService service1;
    @Inject SecondService service2;
    // ... 其他代码
}

依赖类

// FirstService
public class FirstService {
    private static final Logger LOGGER = ...;
    @Inject HttpServletRequest request;
    // ... 其他代码
}

// SecondService
@ApplicationScoped
public class SecondService {
    // ... 其他代码
}

构造注入示例

@Path("hello")
public class HelloResource {
    private final FirstService service1;
    private final SecondService service2;

    @Inject
    public HelloResource(FirstService service1, SecondService service2) {
        // 赋值逻辑
    }
    // ... 其他代码
}

问题1:字段上标注@RequestScoped时,是否会获取到真正的请求作用域注入实例?

答案是不会,CDI的作用域注解(比如@RequestScoped)是用来定义Bean生命周期的,正确的使用位置是类级别,而非注入字段上。

你在service1字段添加的@RequestScoped会被容器直接忽略,此时FirstService没有显式声明作用域,默认会使用CDI的@Dependent(依赖作用域)。这种情况下:

  • JAX-RS资源类HelloResource默认是「每请求一个实例」的模式,每次请求进来都会创建新的HelloResource实例,绑定的FirstService实例也会跟着新建一个。
  • FirstService中注入的HttpServletRequest本身是请求作用域Bean,所以能拿到当前请求的实例,但这和字段上的@RequestScoped无关——完全是因为HttpServletRequest的原生作用域,以及FirstService依赖注入目标生命周期的特性。

如果想让FirstService成为真正的请求作用域Bean,必须把@RequestScoped标注在类上:

@RequestScoped
public class FirstService {
    private static final Logger LOGGER = ...;
    @Inject HttpServletRequest request;
    // ... 其他代码
}

这样不管用哪种注入方式,当前请求范围内都会复用同一个FirstService实例。


问题2:构造函数注入时,@RequestScoped应标注在何处?

规则和字段注入完全一致:@RequestScoped依然要标注在依赖类的类级别(也就是FirstService类上),和构造函数、构造参数无关。

构造注入只是注入的方式,不会改变Bean的作用域属性。所以构造注入场景下,你只需要给FirstService加上类级别的@RequestScoped,HelloResource的构造注入代码不需要做任何作用域相关修改,容器会自动根据FirstService的作用域注入对应请求的实例。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 23:22:46