2011-02-09 67 views
6

我有一個線程安全的對象,創建時需要很高的代價,並且需要通過我的應用程序(一個Lucene.Net IndexReader)來使用。用於Lucene.Net的StructureMap'條件單例'IndexReader

該對象可能會變得無效,此時我需要重新創建它(IndexReader.IsCurrent爲false,需要使用IndexReader.Reopen的新實例)。

我希望能夠使用IoC容器(StructureMap)來管理對象的創建,但是我無法解決這種情況是否可行。這感覺就像某種「有條件的單身人士」生命週期。

StructureMap提供了這樣的功能嗎? 還有其他建議嗎?

回答

3

我可能會使用範圍PerRequest而不是直接返回IndexReader。相反,我會返回一個IndexReader的抽象,它將執行一個在類級別上進行靜態引用的檢查。

然後,當您在墊片/代理/抽象上的屬性被訪問時,它會檢查靜態引用(當然,您會使它成爲線程安全的),並在返回之前重新獲取IndexReader用戶。

+0

我casperOne同意。考慮將實例隱藏在接口/外觀之後,以便更輕鬆地實現諸如對象池的策略。 – Steven 2011-02-09 19:26:48

+0

我考慮過這一點,但從IoC容器中刪除對象創建和生命週期管理的可能性讓人感到羞愧。如果我沒有提出更多以IoC爲中心的話,它肯定會適合我,並且會成爲我的迴歸解決方案。 – 2011-02-09 19:39:38

1

最後,我去了一個簡單的代理對象,它包裝了實際的IndexReader並管理了Reopening。因爲我需要在請求中使用同一個實例,所以我使用StructureMap來提供它的單例實例。下面的代碼。

我已經研究過創建一個自定義的StructureMap ILifecycle來處理這種情況,但沒有得到很遠,請參閱this question

public class IndexReaderProxy 
{ 
    private IndexReader _indexReader; 
    private readonly object _indexReaderLock = new object(); 

    public IndexReaderProxy(Directory directory, bool readOnly) 
    { 
     _indexReader = IndexReader.Open(directory, readOnly); 
    } 

    public IndexReader GetCurrentIndexReader() 
    { 
     ReopenIndexReaderIfNotCurrent(); 
     return _indexReader; 
    } 

    private void ReopenIndexReaderIfNotCurrent() 
    { 
     if (_indexReader.IsCurrent()) return; 
     lock (_indexReaderLock) 
     { 
      if (_indexReader.IsCurrent()) return; 
      var newIndexReader = _indexReader.Reopen(); 
      _indexReader.Close(); 
      _indexReader = newIndexReader; 
     } 
    } 
} 

而且StructureMap登記:

For<IndexReaderProxy>().Singleton().Use(
      new IndexReaderProxy(FSDirectory.Open(new DirectoryInfo(LuceneIndexPath)), true) 
     );