字段标注@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
相关产品推荐
相关产品推荐

