javax.enterprise.context.RequestScoped 在字段上指定时如何工作?
How does javax.enterprise.context.RequestScoped works when is specified on a field?
在代码中发现如下(实名替换为dummy):
JAX-RS 资源
@Path("hello")
public class HelloResource {
@Inject
@RequestScoped
FirstService service1;
@Inject
SecondService service2;
....
}
依赖项
// first
public class FirstService {
private static final Logger LOGGER = ...
@Inject
HttpServletRequest request;
....
}
// second
@ApplicationScoped
public class SecondService { .... }
允许在字段上声明@RequestScoped
。但是在任何地方都找不到它是如何工作的。
问题1:如果我在将被容器注入的字段上指定@RequestScoped
,我会在那里获得请求范围的真实注入实例吗?
问题2:如果我把DI改成constructor-based会怎么样?在这种情况下,我应该把 @RequestScoped
放在哪里?
@Path("hello")
public class HelloResource {
private final FirstService service1;
private final SecondService service2;
@Inject
public HelloResource(FirstService service1, SecondService service2) {
// set values here
}
....
}
我相信 @RequestScoped
和其他范围允许在字段(即 @Target({ TYPE, METHOD, FIELD })
)上仅用于指定 生产者字段 的范围,即它们只有 @Produces
:
才有意义
@Produces
@RequestScoped
Something mySomething;
这里发生了很多很多事情。让我们试着一一解决。
首先,@RequestScoped
是您在制作 的东西上添加的注释。它是一个范围注释,告诉 CDI 正在制作的东西应该存在多长时间。为了保持简单,这可以是 Java class:
@RequestScoped
public class Frobnicator { /* ... */ }
...或者它可以是生产者方法:
@Produces
@RequestScoped
Frobnicator makeRequestScopedFrobnicator() { /* ... */ }
(你 可以 把它放在一个字段上,但在这种极其罕见的情况下,你的字段现在充当生产者 本身 。您可以 read about producer fields,但除了在某些 Java EE 场景中,它们几乎总是错误的方法。在您上面列出的情况下,肯定是 采取错误的方法。)
将 @Inject
和 @RequestScoped
放在任何东西上都没有任何意义。
所以你第一个问题的答案是:没有。
你的第二个问题也可以在通过时被阻止,因为你从来没有在注入场景中使用范围注释(如 @RequestScoped
)。您总是在生产场景中使用它们。
换句话说,当你 @Inject
一些东西时,根据定义,你基本上不知道你刚刚注入的东西在什么范围内;你只需将它用作普通的 POJO,CDI 会负责为你提供正确的东西。
所以在你的情况下,看起来你想要这样:
@Path("hello")
public class HelloResource {
@Inject
FirstService service1;
@Inject
SecondService service2;
/* etc. */
}
…和:
// We'll talk about the lack of annotations here in a moment
public class FirstService {
private static final Logger LOGGER = ...
@Inject
HttpServletRequest request;
/* etc. */
}
就目前而言,这很好,但是 FirstService
有什么范围? CDI 完全知道吗?
那个问题的快速答案分别是:@Dependent
(因为上面没有其他作用域注释)和"probably not"。这几乎肯定不是你想要的。
为了进一步挖掘,您现在必须在档案室 FirstService
中查看您的 META-INF/beans.xml
。如果它表明它在它们上面的 bean-discovery-mode
is annotated
, which is highly likely, then only classes with bean-defining annotations 将被 CDI 发现。因此,由于 FirstService
上没有任何类型的注释,很可能它不会被发现,并且 CDI 会在运行时或启动时的某个时候崩溃,表明没有找到 [=19= 的依赖项].
假设我们将 @ApplicationScoped
放在 FirstService
上。这将使 FirstService
基本上成为一个单例(同样,保持简单)。但是等等,你说,HttpServletRequest
呢?那将在什么范围内?答案是:作为消费者的你不知道,也不关心。 (真正的答案当然是它会反映当前请求,所以很可能在请求范围内。)任何时候你试图访问那个 HttpServletRequest
字段,你最好在一个请求中,或者它会炸毁你的。
或者您可以将 @RequestScoped
放在 FirstService
上,在这种情况下,访问 FirstService
类型字段的任何内容最好在访问时处于活动请求范围内,或者,再次,这一切都会在你身上爆炸。
最后,您是在 JAX-RS 的上下文中执行所有这些操作,它在 CDI 诞生之前就有自己的依赖项注入框架。为了让 JAX-RS 和 CDI 相对更好地协同工作,需要将方形钉子敲入圆孔中。其中一种情况是,严格来说资源 classes 不支持 CDI 样式的构造函数注入,仅支持 JAX-RS 样式的构造函数注入,这是它自己的(已弃用)主题。因此,对于资源 classes,您通常希望保留字段注入。
此外,JAX-RS 应用程序不需要 Servlet 构造。事实上,根据基础架构的特定组合,您 运行、@Inject private HttpServletRequest request
可能也不起作用,您可能必须使用 @Context
。 (这是它自己的一套问题和答案。)
在代码中发现如下(实名替换为dummy):
JAX-RS 资源
@Path("hello")
public class HelloResource {
@Inject
@RequestScoped
FirstService service1;
@Inject
SecondService service2;
....
}
依赖项
// first
public class FirstService {
private static final Logger LOGGER = ...
@Inject
HttpServletRequest request;
....
}
// second
@ApplicationScoped
public class SecondService { .... }
允许在字段上声明@RequestScoped
。但是在任何地方都找不到它是如何工作的。
问题1:如果我在将被容器注入的字段上指定@RequestScoped
,我会在那里获得请求范围的真实注入实例吗?
问题2:如果我把DI改成constructor-based会怎么样?在这种情况下,我应该把 @RequestScoped
放在哪里?
@Path("hello")
public class HelloResource {
private final FirstService service1;
private final SecondService service2;
@Inject
public HelloResource(FirstService service1, SecondService service2) {
// set values here
}
....
}
我相信 @RequestScoped
和其他范围允许在字段(即 @Target({ TYPE, METHOD, FIELD })
)上仅用于指定 生产者字段 的范围,即它们只有 @Produces
:
@Produces
@RequestScoped
Something mySomething;
这里发生了很多很多事情。让我们试着一一解决。
首先,@RequestScoped
是您在制作 的东西上添加的注释。它是一个范围注释,告诉 CDI 正在制作的东西应该存在多长时间。为了保持简单,这可以是 Java class:
@RequestScoped
public class Frobnicator { /* ... */ }
...或者它可以是生产者方法:
@Produces
@RequestScoped
Frobnicator makeRequestScopedFrobnicator() { /* ... */ }
(你 可以 把它放在一个字段上,但在这种极其罕见的情况下,你的字段现在充当生产者 本身 。您可以 read about producer fields,但除了在某些 Java EE 场景中,它们几乎总是错误的方法。在您上面列出的情况下,肯定是 采取错误的方法。)
将 @Inject
和 @RequestScoped
放在任何东西上都没有任何意义。
所以你第一个问题的答案是:没有。
你的第二个问题也可以在通过时被阻止,因为你从来没有在注入场景中使用范围注释(如 @RequestScoped
)。您总是在生产场景中使用它们。
换句话说,当你 @Inject
一些东西时,根据定义,你基本上不知道你刚刚注入的东西在什么范围内;你只需将它用作普通的 POJO,CDI 会负责为你提供正确的东西。
所以在你的情况下,看起来你想要这样:
@Path("hello")
public class HelloResource {
@Inject
FirstService service1;
@Inject
SecondService service2;
/* etc. */
}
…和:
// We'll talk about the lack of annotations here in a moment
public class FirstService {
private static final Logger LOGGER = ...
@Inject
HttpServletRequest request;
/* etc. */
}
就目前而言,这很好,但是 FirstService
有什么范围? CDI 完全知道吗?
那个问题的快速答案分别是:@Dependent
(因为上面没有其他作用域注释)和"probably not"。这几乎肯定不是你想要的。
为了进一步挖掘,您现在必须在档案室 FirstService
中查看您的 META-INF/beans.xml
。如果它表明它在它们上面的 bean-discovery-mode
is annotated
, which is highly likely, then only classes with bean-defining annotations 将被 CDI 发现。因此,由于 FirstService
上没有任何类型的注释,很可能它不会被发现,并且 CDI 会在运行时或启动时的某个时候崩溃,表明没有找到 [=19= 的依赖项].
假设我们将 @ApplicationScoped
放在 FirstService
上。这将使 FirstService
基本上成为一个单例(同样,保持简单)。但是等等,你说,HttpServletRequest
呢?那将在什么范围内?答案是:作为消费者的你不知道,也不关心。 (真正的答案当然是它会反映当前请求,所以很可能在请求范围内。)任何时候你试图访问那个 HttpServletRequest
字段,你最好在一个请求中,或者它会炸毁你的。
或者您可以将 @RequestScoped
放在 FirstService
上,在这种情况下,访问 FirstService
类型字段的任何内容最好在访问时处于活动请求范围内,或者,再次,这一切都会在你身上爆炸。
最后,您是在 JAX-RS 的上下文中执行所有这些操作,它在 CDI 诞生之前就有自己的依赖项注入框架。为了让 JAX-RS 和 CDI 相对更好地协同工作,需要将方形钉子敲入圆孔中。其中一种情况是,严格来说资源 classes 不支持 CDI 样式的构造函数注入,仅支持 JAX-RS 样式的构造函数注入,这是它自己的(已弃用)主题。因此,对于资源 classes,您通常希望保留字段注入。
此外,JAX-RS 应用程序不需要 Servlet 构造。事实上,根据基础架构的特定组合,您 运行、@Inject private HttpServletRequest request
可能也不起作用,您可能必须使用 @Context
。 (这是它自己的一套问题和答案。)