在代码中找到以下内容(真实名称替换为虚拟名称:]
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更改为基于构造函数该怎么办?在这种情况下,我应将@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
是您在正在[
@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完全了解吗?对
that
@Dependent
(因为上面没有其他作用域注释)和“可能不是”。几乎可以肯定这不是您想要的。要进行进一步的挖掘,现在您必须查看存档外壳META-INF/beans.xml
中的FirstService
。如果它指示很有可能是其bean-discovery-mode
is annotated
,则CDI将仅发现上面带有bean-discovery-mode
的类。因此,由于annotated
上没有任何类型的注释,因此很可能不会被发现,并且CDI将在运行时或启动时爆炸,这表明没有找到bean-defining annotations的依赖项。假设我们将FirstService
放在FirstService
上。这将使@ApplicationScoped
基本为单例(同样,保持简单)。但是,等等,您说FirstService
呢?那将是什么范围?答案是:作为消费者的您不知道,并且您不在乎。 (当然,真正的答案是它将反映当前请求,因此很可能在请求范围内。)任何时候尝试访问该FirstService
字段时,最好都在请求中,否则它会失败靠你。
或者您可以将HttpServletRequest
放在HttpServletRequest
上,在这种情况下,访问@RequestScoped
类型字段的任何内容最好在访问时都处于活动请求范围内,否则,它都会全部消失靠你。
最后,您要在JAX-RS的上下文中完成所有这些工作,在JAX-RS诞生之前,它就有自己的依赖项注入框架。为了使JAX-RS和CDI相对较好地配合使用,需要将方形钉大量敲入圆孔。其中一种情况是严格说来,资源类不支持CDI样式的构造函数注入,而仅支持JAX-RS样式的构造函数注入,这是它自己的(不建议使用)主题。因此,对于资源类,您通常希望保留字段注入。
而且,JAX-RS应用程序不需要Servlet构造。实际上,根据您所使用的基础结构的特定组合,FirstService
可能也不起作用,您可能必须使用FirstService
。 (这是它自己的一组问题和答案。)
@Inject private HttpServletRequest request
和其他范围仅用于指定生产者字段的范围,即仅对@Context
才有意义。@Context