2014-12-06 70 views
2

Guice有以下問題:單身服務,注入上下文敏感信息的提供者。到現在爲止,背景下只涉及到Servlet請求,所以我用一個@RequestScoped提供商,而我這個注射提供商的服務,像這樣:使用來自兩個不同範圍的提供者

@RequestScoped 
public class ContextProvider<IContext> implements Provider<IContext> { 
    @Override 
    public IContext get() { ... } // returns context   
} 

@Singleton 
public class ServiceImpl implements IService { 

    @Inject 
    private Provider<IContext> contextProvider; 

} 

這工作正常。現在,我正在爲應用程序添加後臺任務處理。後臺任務不是從Web請求發起的,所以我不能使用ServletScopes.scopeRequest(..)。我已經編寫了一個自定義範圍(幾乎是Giuce doc中BatchScoped的精確副本),以使每個任務都在其自己的範圍內運行。現在的問題是 - 如何使BatchScoped ContextProvider和配置Guice使用它?

我做了這樣的嘗試與結合EDSL:

line 1 : bind(IContext.class).toProvider(ContextProvider.class).in(RequestScoped.class); 
line 2 : bind(IContext.class).toProvider(BatchContextProvider.class).in(BatchScoped.class); 

但吉斯告訴我,第2行是「A結合IContext已經配置在第1行」。

問題是:用Guice做這種注射的正確方法是什麼?

+0

我不明白你爲什麼不能使用'ServletScopes.scopeRequest()',這正是它的設計目的。 – 2014-12-06 22:39:01

+0

我無法使用它,因爲後臺任務不是從Web請求發起的。所以沒有RequestScope是可用的。 – execc 2014-12-07 10:37:46

+1

你試過了嗎?我認爲你會發現'scopeRequest()'做的是:它會產生一個「假」請求範圍。 – 2014-12-07 17:21:16

回答

2

一個類似的問題:Getting multiple guice singletons of the same type

總的來說這裏的問題是,你想在同一類綁定到兩個不同的供應商(和範圍,但實際上是跑題了)。

bind(IContext.class) 
    .annotatedWith(MyAnnotation1.class) 
    .toProvider(ContextProvider.class) 
    .in(RequestScoped.class); 
bind(IContext.class) 
    .annotatedWith(MyAnnotation2.class) 
    .toProvider(BatchContextProvider.class) 
    .in(BatchScoped.class); 

並改變注射部位包括相關注釋:如果你使用的獨特結合註解爲每一個,像這樣只可能

@Inject 
@MyAnnotationX 
private Provider<IContext> contextProvider; 
+0

謝謝你的回答。你可以請,解釋一件事 - 我的服務是一個單身人士,因此,只有一個注射部位。我應該注入兩個提供程序,並使用非空值?或者設計一些代表,女巫是否可以(可能直接使用注射器?) – execc 2014-12-07 10:40:45

+0

哦,我誤解了。我認爲塔維安的聲明聽起來對你的要求來說是合理的,試試吧。如果這不起作用,假設你有一些其他的scope scope注入狀態變量,你可以通過注入它作爲提供者參數來讓你的提供者切換,但這聽起來很醜陋。 – The111 2014-12-07 22:20:50

0

你需要一個請求開頭你的背景任務,並保持它的所有。這就是ServletScopes.scopeRequest

public class MyBackgroundTask extends Thread { 
    @Override 
    public void run() { 
     RequestScoper scope = ServletScopes.scopeRequest(Collections.emptyMap()); 
     try (RequestScoper.CloseableScope ignored = scope.open()) { 
      doTask(); 
     } 
    } 

    private void doTask() { 

    } 
} 

哦,不要忘記使用提供程序,以便延遲檢索依賴項。例如,展示前面的示例,以便後臺任務使用您的IContext

public class MyBackgroundTask extends Thread { 
    private Provider<IContext> contextProvider; 

    @Inject 
    public MyBackgroundTask(Provider<IContext> contextProvider) { 
     this.contextProvider = contextProvider; 
    } 

    @Override 
    public void run() { 
     RequestScoper scope = ServletScopes.scopeRequest(Collections.emptyMap()); 
     try (RequestScoper.CloseableScope ignored = scope.open()) { 
      doTask(); 
     } 
    } 

    private void doTask() { 

    } 
} 

如果不使用供應商的注入,在這個例子中,將從創建這可能是內部的另一個範圍的後臺任務的線程中完成的。

BONUS:您可能已經注意到作爲參數發送給scopeRequest方法的空映射。檢查Guice javadocs。這些是你想要在你的假請求範圍內出現的實例。根據您的IContext您可能需要它。

相關問題