2010-08-23 76 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​​ :)