2010-08-23 79 views
1

我想正確設置一個服務器端緩存,我正在尋找建設性的批評,我目前的設置。緩存在Servlet啓動時加載並且再也不會更改,所以實際上它是一個只讀緩存。它顯然需要留在內存中的Servlet的生命週期。以下是我把它設置正確設置一個簡單的服務器端緩存

private static List<ProductData> _cache; 
private static ProductManager productManager; 

private ProductManager() { 
    try { 
     lookup(); 
    } catch (Exception ex) { 
     _cache = null; 
    } 
} 

public synchronized static ProductManager getInstance() { 
    if (productManager== null) { 
     productManager= new ProductManager(); 
    } 
    return productManager; 
} 

緩存是由Servlet設置如下:

private ProductManager productManager; 

public void init(ServletConfig config) throws ServletException { 
    productManager = ProductManager.getInstance(); 
} 

最後,這是我訪問:

public static ProductData lookup(long id) throws Exception { 
    if (_cache != null) { 
     for (int i = 0; i < _cache.size(); i++) { 
      if (_cache.get(i).id == id) { 
       return _cache.get(i); 
      } 
     } 
    } 

    // Look it up in the DB. 
} 

public static List<ProductData> lookup() throws Exception { 
    if (_cache != null) { 
     return _cache; 
    } 

    // Read it from the DB. 

    _cache = list; 
    return list; 
} 

回答

1

你這樣做是困難的。單體味的模式是完全不必要的。只需實現一個ServletContextListener以在webapp啓動(和關閉)上掛鉤,以便您可以在webapp啓動期間將數據加載並存儲在應用程序範圍中。

<listener> 
    <listener-class>com.example.Config</listener-class> 
</listener> 

這樣,您就可以得到它在任何Servlet如下:

Config config = Config.getInstance(getServletContext()); 
Map<Long, Product> products = config.getProducts(); 
// ... 
0

我會建議您將緩存作爲散列圖:

private static HashMap<Long,ProductData> _cache = new HashMap<Long,ProductData>(); 


// lookup by id becomes 
return _cache.get(id); 

// lookup of the complete collection of ProductData : 
return _cache.values(); 

您可以將緩存設置爲ProductData類中的靜態字段,以減少耦合和移動部分。

使用按id查找的散列圖將基本保持恆定時間,而當forData循環隨着時間的推移而增加時,使用for循環的搜索將增加。

1

涌現在腦海有幾件事情:

  • 存儲緩存的ProductData情況下在一張地圖,這樣你可以看一下在固定時間內緩存的實例,而不必通過列表來搜索。
  • lookup方法不是線程安全的。
  • 只有lookup()會實際加載數據庫中的值:您不希望其他lookup方法也加載緩存(如果尚未加載)以加快檢索單個的ProductData實例嗎?
+0

如何,特別是,我應該去了解線程

public class Config implements ServletContextListener { private static final String ATTRIBUTE_NAME = "com.example.Config"; private Map<Long, Product> products; @Override public void contextInitialized(ServletContextEvent event) { ServletContext context = event.getServletContext(); context.setAttribute(ATTRIBUTE_NAME, this); String dbname = context.getInitParameter("dbname"); products = Database.getInstance(dbname).getProductDAO().map(); } @Override public void contextDestroyed(ServletContextEvent event) { // NOOP. } public static Config getInstance(ServletContext context) { return (Config) context.getAttribute(ATTRIBUTE_NAME); } public Map<Long, Product> getProducts() { return products; } } 
您在web.xml註冊如下

安全?同步塊和/或併發集合類? – bluedevil2k 2010-08-23 21:38:35

+0

併發集合不會對您有所幫助,因爲我相信您正在加載緩存一次,在此之後它不會更改。第二個'lookup'方法 - 實際上加載緩存 - 需要被「同步」。否則兩個線程都會發現'_cache'是'null',可能都會嘗試從數據庫加載。 – 2010-08-28 21:21:52

0

請看番石榴的Suppliers.memoizeWithExpiration()和MapMaker。這兩個(在你的情況下,我認爲MapMaker更相關)將允許你在幾分鐘內創建一個緩存功能。

保存自己一些頭痛,使用API​​ :)