簡體   English   中英

如何從第三方為@Inject 設置非 CDI bean 到 CDI bean

[英]How to setup a non-CDI bean from a 3rd party for @Inject into CDI bean

雖然我在 CDI 中找到了設置@Produces (有點像工廠)或使用 CDI javax.enterprise.inject.spi.Unmanaged概念的javax.enterprise.inject.spi.Unmanaged ,但它們似乎都假定 CDI 將是創建類實例的對象根據其自身的條款和生命周期(這是有道理的)。

但是,在某些情況下,CDI 根本無法創建實例。

例如在內部創建對象並將其提供給您的第 3 方庫(不使用 CDI 本身)。

現在,我該如何獲取這些已經實例化的對象(順便說一下,它們是沒有默認構造函數的最終對象),然后讓它們可供我的 CDI 托管 bean 使用?

這是一個簡化的示例。

public class Foo
{
    @Inject
    private ByteBuffer buf;

    public void go()
    {
        // do something, with buffer
    }
}

public void process() {
    ByteBuffer buf = ByteBuffer.allocate(500);
    // TODO: how to add "buf" to current context?
    Foo foo = CDI.current().select(Foo.class,AnyLiteral.INSTANCE).get();
    foo.go();
}

現在,我意識到對於這個特定的例子,我可以輕松地傳入 ByteBuffer,或者為 ByteBuffer 設置一個@Produces ,或者甚至讓 Foo 自己制作 ByteBuffer。 (所有這些都會更容易)。 我選擇了 ByteBuffer,因為它展示了我在使用 3rd 方庫時遇到的相同問題

  • 實例是有效的 bean
  • 我無法控制它的來源
  • 實例由庫創建
  • 這些實例是final ,不能被包裝、覆蓋或代理

用例也有嵌套 CDI 引用的情況,這些引用也可以使用對這個@Inject ByteBuffer buf;訪問@Inject ByteBuffer buf; .

理想情況下,希望它成為一種純粹的 CDI api 技術,而不是特定於焊接或實現的東西。

我也研究了自定義 Scope 創建,認為這可能是一個解決方案,有一種@BufferScope來標識這個實例的start()end() 但沒有一個實例和文檔使這個非常清楚至於對象CDI只是不能打電話newInstance()produce()上。 對象實例化不在我的掌控之中,但可以將其呈現給 CDI 范圍,甚至可以管理該實例的最終死亡/銷毀。

代理與包裝不同。 一種習慣的解決方法是創建一個ByteBufferHolder (在此處插入您的類),它將自定義構建器流調整為一個理解它位於 DI 上下文內的 bean。

我不確定我是否同意 CDI 假設它正在構建實例的原始斷言。 例如,我在 JSF 應用程序中使用以下內容來注入當前的 FacesContext 實例....

import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Produces;
import javax.faces.context.FacesContext;

public class FacesContextProducer {

    @Produces @RequestScoped FacesContext getFacesContext() {
        return FacesContext.getCurrentInstance();
    }
}

我無處創建 FacesContext 實例。 所需要的只是外部框架創建的內容是可訪問的。

那么,如果您從外部來源獲取實例,只要您能獲得正確的實例,@Produces 方法是否仍然有效?

這里有一些根本性的誤解。 CDI 不需要構造它可以通過生產者方法提供服務的 bean 實例。 如果該類不可代理,則 Dependent 作用域將正常工作。 您還可以為對象創建一個包裝類,並將所述類實例放在您需要的任何范圍內。

您使用生產者方法,它可以像這樣簡單:

@Produces
@ApplicationScoped
private Foo produceFoo() {
  final Foo instance = // acquire one of those instances you're talking about
  return instance;
}

如果出於某種原因對您不起作用,您也可以編寫一個可移植的擴展並以編程方式添加一個可以執行您想要的操作的Bean 所以在 CDI 2.0+ 中是這樣的(未經測試):

private void afterBeanDiscovery(@Observes final AfterBeanDiscovery event) {
  final Foo instance = // acquire one of these final instances you're talking about
  event.addBean()
    .scope(ApplicationScoped.class)
    .qualifiers(whateverYouNeed)
    .addTransitiveTypeClosure(instance.getClass())
    .createWith(cc -> instance) // you may also need .destroyWith()
    ;
}

一旦你設置了這個“生產端”,然后在任何 CDI bean 中你可以做的任何事情:

@Inject
private Foo foo;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM