在字段上指定javax.enterprise.context.RequestScoped如何工作?

问题描述 投票:0回答:2

在代码中找到以下内容(真实名称替换为虚拟名称:]

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
  }

  ....

}
java scope cdi java-ee-8
2个回答
3
投票

这里有很多很多事情。让我们尝试一个接一个地解决它们。

首先,@RequestScoped是您在正在[上放置的注释。它是一个范围注释,它告诉CDI制造的东西应该活多久。为了简单起见,这可以是Java类:

@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。 (这是它自己的一组问题和答案。)


0
投票
我相信@Inject private HttpServletRequest request和其他范围仅用于指定

生产者字段的范围,即仅对@Context才有意义。@Context

© www.soinside.com 2019 - 2024. All rights reserved.