有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何处理javax。企业上下文在字段上指定RequestScope时,RequestScope工作?

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

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
  }

  ....

}

共 (2) 个答案

  1. # 1 楼答案

    我认为@RequestScoped和其他作用域仅在指定生产者字段的作用域时才允许在字段(即@Target({ TYPE, METHOD, FIELD }))上使用,也就是说,它们仅在@Produces时才有意义:

    @Produces
    @RequestScoped
    Something mySomething;
    
  2. # 2 楼答案

    这里发生了很多很多事情。让我们试着一个接一个地解决它们

    首先,@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知道吗

    这个问题的快速答案分别是:@Dependent(因为上面没有其他范围注释)和“可能没有”。这几乎肯定不是你想要的

    为了进一步挖掘,你现在必须查看档案室中的META-INF/beans.xml。如果它指出它的^{} is ^{}(可能性很大),那么CDI只会发现上面有bean-defining annotations的类。因此,由于FirstService上没有任何类型的注释,它很可能不会被发现,CDI将在运行时或启动时爆炸,表明没有找到FirstService的依赖项

    假设我们把@ApplicationScoped放在FirstService上。这将使FirstService基本上成为一个单例(同样,保持简单)。但是等等,你说,那HttpServletRequest呢?这将在什么范围内?答案是:作为消费者,你不知道,也不在乎。(真正的答案当然是,它将反映当前的请求,因此很可能在请求范围内。)每当你试图访问HttpServletRequest字段时,你最好是在请求中,否则它会向你发起攻击

    或者你可以把@RequestScoped放在FirstService上,在这种情况下,任何访问FirstService类型字段的东西最好在访问时处于活动的请求范围内,否则,它会再次在你身上爆炸

    最后,您将在JAX-RS的环境中完成所有这些工作,在CDI诞生之前,JAX-RS有自己的依赖注入框架。要使JAX-RS和CDI能够相对良好地配合使用,需要大量将方形的钉子敲入圆孔。其中一种情况是,严格来说,资源类不支持CDI风格的构造函数注入,只支持JAX-RS风格的构造函数注入,这是它自己的主题(不推荐使用)。因此,对于资源类,您通常希望继续使用字段注入

    此外,JAX-RS应用程序不需要Servlet构造。事实上,根据您运行的基础设施的特定组合,@Inject private HttpServletRequest request可能也不起作用,您可能必须使用^{}。(这是它自己的一套问题和答案。)