2017-11-04 122 views
1

我有一個使用PlayFramework 2.6.5和Guice DI(libraryDependencies += guice)構建的Java web服務,正好是時間注入模式。所有依賴項通過構造函數注入,使用@Inject@ImplementedBy,而Guice Module爲空。`ProvisionException`被高速緩存,構造函數代碼永遠不會被重試

由於瞬態錯誤,一些依賴可以在構造函數中拋出異常。發生這種情況時,服務將失敗,並顯示ProvisionException(這沒關係,客戶端需要重試)。

我發現這些異常被緩存,即使解決了異常的根本原因,Play或Guice都不會重試實例化這些類,並在Web服務重新啓動之前繼續拋出相同的異常。

例如,考慮下面的類Clock,它的構造函數在午夜(00:xx)時失敗。只要系統時鐘到達午夜,服務就無法實例化該類。當時鍾達到凌晨1點時,相同的異常不斷被拋出。此外,異常消息總是相同(本例中的異常消息是第一時間發生異常的時間)

@ImplementedBy(OddClock.class) 
public interface IClock { 
    //... 
} 

public class OddClock implements IClock { 
    @Inject 
    public OddClock() throws Exception { 
     if (DateTime.now().hourOfDay().get() == 0) { 
      throw new Exception(DateTime.now().toString()); 
     } 
    } 
} 

public class TimeController { 
    @Inject 
    public TimeController(IClock clock) { 
     this.clock = clock; 
    } 
} 

順便說一句,相同的基本代碼還用於在控制檯應用程序,它沒有按」不會遇到這個問題,所以我認爲Play + Guice集成有一些特殊之處。任何建議關閉異常緩存?

回答

0

我發現了一個解決方案,使PF的行爲更加明確和可預測。由PF默認生成的路由緩存控制器,即使它們的實例被破壞,假設singleton控制器是用戶想要的。

here所述,可以在路由配置中的每個操作之前添加@,更改默認行爲。

例如前:

GET /test webservice.TestController.test 

後:

GET /test @webservice.TestController.test 

有了這個語法,控制器不能單按默認值,仍然可以使用@Singleton需要的地方。此外,單例控制器在異常情況下不會被緩存,從而在不重新啓動服務的情況下恢復瞬態錯誤。 代碼副本可用here

1

拋出異常並緩存異常看起來像Guice中的內置行爲。這也是一種公平的行爲,因爲Guice期望它創建的對象避免IO和其他非確定性行爲。

https://github.com/google/guice/wiki/BeCarefulAboutIoInProviders

提供商沒有定義重試策略。當值不可用時,多次調用get()可能會導致多個失敗的規定。

您可以通過改變範圍您使用,使該實例每次重新創建,以避免緩存。例如。使用臨時範圍代替單身人士。

在我看來,更好的解決方案是獲取不可靠的對象,並將其包裝在隱藏故障和處理重試的另一個對象中。這種方式Guice在嘗試創建可靠的對象時總是會成功,並且您可以在可靠的包裝器中添加自己的失敗處理代碼。

例如一個簡單的例子,重試建設:

public class ReliableClock { 
    private Factory<Clock> clockFactory; 
    private Clock internalClock; 
    public ReliableClock(Factory<Clock> clockFactory) { 
    this.clockFactory = clockFactory; 
    } 
    private synchronized Clock currentClock() throws Exception { 
    if (clock == null) { 
     clock = clockFactory.create() // May throw exception 
    } 
    return clock; 
    } 
    // ... methods ... 
} 
+0

這將工作。我不禁感到,重新設計'IClock'實現以避免在構造函數中引發異常會更加整潔。難道這種驗證不能懶惰地完成嗎? – Graham

+0

我同意,如果有可能解決根本原因的異常,那麼這將是一個更好的方法。 –

+0

感謝您的建議,我同意理想情況下可以改進代碼,但不幸的是,在真實情況下情況並非如此(上面的例子是說明問題的一個非常簡單的例子)。 @RichDougherty:_拋出異常並緩存異常看起來像Guice中的內置行爲。我仍然不明白爲什麼這個問題隻影響Web服務而不影響控制檯應用程序(請參閱我的最後一句),儘管,兩人都在使用Guice。 Play框架控制器是否被實例化爲單例? –

相關問題