在 CDI 中,如何在注入点为 bean 赋予范围?

In CDI, how to give scope to a bean at the point of injection?

在 CDI 中,我能够注入一个具有特定范围的 bean,该范围定义了 bean class。但是,如果我创建没有任何作用域的 bean class 并在注入时为该 bean 赋予作用域会怎样。我的要求是在后一种情况下使注入时间范围界定成为可能。问题是注入发生在 dependent scope 而不是所需的注释范围,除非我使用 producer.

例如:

案例 1:

当我在其 class 声明中声明 bean 的范围时,如下所示:

@ApplicationScoped
class UserDetails {
...
}

并像这样注入:

@ViewScoped
class UserView {

    @Inject
    UserDetails userDetails;
    .
    .
}

它按预期工作。在应用程序范围内注入的 bean 在整个应用程序中的所有其他 bean 中都可用。


案例 2:

但是当我在 class 声明中没有给出范围时:

class UserDetails {
...
}

并像这样注入(在注入点给出范围):

@ViewScoped
class UserView {

    @Inject @ApplicationScoped
    UserDetails userDetails;
    .
    .
}

这失败了!...注入的 bean 没有注入 application scope,而是注入了 dependent scope(在我的例子中是 View Scope)。

我必须创建一个 Producer 和一个 Qualifier,其中 @Produces 方法在所需的 application scope 中提供 bean。在这种情况下,如果我必须在 application scope 中注入 bean class UserDetails,我觉得这个 producer/qualifier 扩展是一个开销。

事实是,UserDetails class 是第三方 jar 的一部分。这个 class 没有声明任何范围,是一个 POJO。我无法更改其源代码。

根据以上讨论,我有两个问题:

  1. 为什么有人知道要在特定范围内注入 bean 时会创建未定义范围的 bean classes?这种做法对设计有什么好处吗?

  2. 因为我无法控制 bean classes 的源代码,并且它们与任何范围都没有关联,所以 producer/qualifier 扩展是唯一的好方法吗在所需的范围内注入这样的豆?

1.未定义范围的对象 - 使用@Dependent

CDI 会将没有范围的对象视为 @Dependent scope

An instance of a dependent bean is never shared between different clients or different injection points. It is strictly a dependent object of some other object. It is instantiated when the object it belongs to is created, and destroyed when the object it belongs to is destroyed.

Beans with scope @Dependent don’t need a proxy object. The client holds a direct reference to its instance.

Spring IoC dev: CDI @Dependent scope is similar to Spring IoC Prototype scope.

2。没有 @Produces & 只使用 @Inject

CDI 将为每次注入创建新的 UserDetails 实例(@Dependent 范围)。这里没有共享数据!您不能像以前那样定义作用域(注入时)。

3。使用@Produces & 使用@Inject

您可以控制 UserDetails 对象的范围(ApplicationScoped、SessionScoped 或 RequestScoped)

public class Producers {

     @Produces @ApplicationScoped
     public UserDetails createUserDetails() {
         // Initialize UserDetails
     }

     public void release(@Disposes UserDetails userDetails) {
         // Release userDetails if you have to
     }
}

4.另一种方法:尽可能扩展 UserDetails

    @ApplicationScoped // Or @SessionScoped, @RequestScoped
    public class UserDetailsImpl extends UserDetails {
        //
    } 

如果你想要 UserDetails 的 ApplicationScoped。方式3或者方式4都可以。

作用域总是在 bean 上定义,而不是在注入点上。

注入点不能改变注入bean的范围。

我认为您可以通过在注入点附近指定 @New 注释将 @ApplicationScoped bean 作为 @Dependent bean 注入,但您不能相反。