在 Java EE CDI 中,如何始终知道 CDI bean 应声明为什么范围?

In Java EE CDI how is it possible to always know what scope a CDI bean should be declared as?

我正在学习 Java EE 8 教程,新手对作用域有些困惑。我对此很陌生,所以如果这是一个愚蠢的问题,请多多包涵。 我的理解是,CDI 允许任何 class 被注解为一个范围,例如 @RequestScoped 被注入到一个 Servlet 中。 https://javaee.github.io/tutorial/cdi-basic001.html 教程中给出的例子是

@RequestScoped
public class MessageB implements Message { ... }

允许这样做:

@WebServlet("/cdiservlet")
public class NewServlet extends HttpServlet {
    @Inject private Message message;

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response)
                  throws IOException {
        response.getWriter().write(message.get());
    }
}

这一切都很好,也很容易理解,但是......

我的问题是,这不是限制 and/or 在 servlet 中使用 MessageB class 吗?如果要用作 CDI bean 的 class 需要在一个用例、servlet 或应用程序的请求范围内使用,而在另一个用例的会话范围内使用,并且可能在另一个用例的应用程序范围内使用怎么办?这应该如何工作? class 开发者作者是否应该设想尽可能广泛的范围(尤其是在编写将被其他开发者使用的 class 时)?如果是这样,如果使用 class 的客户端想要在请求范围内使用它怎么办? 看起来我们应该有松散耦合的代码,但是将 class 绑定到范围限制了 class 可以以可能无用或不合逻辑的方式使用的方式。 还是总是假定像这样使用的 bean 是由应用程序开发人员编写的 him/herself?
提前感谢您的任何见解。

编辑: 更进一步看来 @Qualifier 是这些问题的解决方案。开发人员需要提供不同的子类型(例如,通过实现接口或扩展 class),然后对每个不同的类型使用 @Qualifier 属性。

https://javaee.github.io/tutorial/cdi-basic006.html

https://dzone.com/articles/define-cdi-qualifier

是的,您可以使用不同的 CDI 作用域 Message 接口的不同 CDI Bean。这种方法的最佳实践是定义多个注释,例如

@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface SessionMessage {}

然后您可以添加 @SessionMessage 例如在您的 @SessionScope bean 上方并使用 @Inject @SessionMessage private Message message.

注入此消息 bean

另一种方法可能是 CDI 的默认 @Dependet 范围,如果您没有在 CDI bean 上定义任何范围,则使用它。使用此范围,您可以实现以下目标:

@Dependent: The default scope if none is specified; it means that an object exists to serve exactly one client (bean) and has the same lifecycle as that client (bean). (https://docs.oracle.com/javaee/6/tutorial/doc/gjbbk.html)

使用此注释,您可以继承客户端 bean 的范围。因此,如果您将 Message 注入 @RequestScoped bean,您的 Message 将具有相同的生命周期。