我正在开发一个Java Web应用程序,它通过从Web服务加载的大型XML配置文件来实现它的行为.由于在访问应用程序的特定部分之前实际上不需要这些文件,因此它们会被懒惰地加载.当需要其中一个文件时,会向Web服务发送查询以检索相应的文件.由于某些配置文件可能会被大量使用,更经常比别人我想建立某种形式的缓存(有可能1个小时的过期时间),以避免一遍又一遍请求相同的文件.
对于所有会话中的所有用户,Web服务返回的文件都是相同的.我不使用JSP,JSF或任何其他花哨的框架,只是简单的servlet.
我的问题是,在Java Web应用程序中实现这样一个全局静态缓存的最佳实践是什么?单例类是否合适,或者由于J2EE容器会有奇怪的行为吗?我应该通过JNDI在某处暴露某些东西吗?我该怎么做才能使我的缓存不会在集群环境中搞砸(每个集群服务器有一个缓存可以,但不是必需的)?
鉴于上面的信息,将一个负责缓存的对象作为ServletContext属性是否是正确的实现?
注意:我不想在启动时加载所有这些并完成它因为那样
1).每当我的应用程序启动时重载webservice
2).我的应用程序运行时文件可能会更改,所以无论如何我都要重新查询它们
3).我仍然需要一个全局可访问的缓存,所以我的问题仍然存在
更新:使用缓存代理(例如squid)可能是一个好主意,但是对webservice的每个请求都会在post Data中发送相当大的XML查询,每次都可能不同.只有Web应用程序才真正知道对Web服务的两个不同调用实际上是等效的.
谢谢你的帮助
以下是使用EhCache进行缓存的示例.此代码在多个项目中用于实现临时缓存.
1)将缓存放在全局上下文中.(不要忘记在WEB.XML中添加监听器).
import net.sf.ehcache.Cache; import net.sf.ehcache.CacheManager; public class InitializationListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { ServletContext ctx = sce.getServletContext(); CacheManager singletonManager = CacheManager.create(); Cache memoryOnlyCache = new Cache("dbCache", 100, false, true, 86400,86400); singletonManager.addCache(memoryOnlyCache); cache = singletonManager.getCache("dbCache"); ctx.setAttribute("dbCache", cache ); } }
2)在需要时检索缓存实例.即来自servlet:
cache = (Cache) this.getContext().getAttribute("dbCache");
3)在执行昂贵的操作之前查询缓存.
Element e = getCache().get(key); if (e != null) { result = e.getObjectValue(); // get object from cache } else { // Write code to create the object you need to cache, then store it in the cache. Element resultCacheElement = new Element(key, result); cache.put(resultCacheElement); }
4)也不要忘记在适当的时候使缓存的对象无效.
你可以在这里找到更多样品
您的问题包含几个单独的问题.让我们慢慢开始.ServletContext是一个可以存储缓存句柄的好地方.但是你需要为每个服务器实例提供缓存.应该没问题.如果要在更大范围内注册缓存,请考虑将其注册到JNDI中.
缓存的问题.基本上,您是通过webservice检索xml.如果您通过HTTP访问此Web服务,您可以在您的旁边安装简单的HTTP代理服务器来处理xml的缓存.下一步是在某种本地对象缓存中缓存已解析的xml.每个服务器可以存在此缓存而没有任何问题.在第二种情况下,EHCache将做得很好.在这种情况下,处理链将是这样的Client - http request -> servlet -> look into local cache - if not cached -> look into http proxy (xml files) -> do proxy job (http to webservice)
.
优点:
每个服务器实例的本地缓存,仅包含来自请求的xmls的对象
一个http代理在与我们的webapp相同的硬件上运行.
可以在不为xml文件添加新的http代理的情况下扩展webapp.
缺点:
下一级基础设施
+1点失败(http代理)
更复杂的部署
更新:不要忘记始终将HTTP HEAD请求发送到代理中以确保缓存是最新的.
选项#1:使用开源缓存库,如EHCache
当有许多优秀的开源替代方案可以插入并开始使用时,不要实现自己的缓存.实现自己的缓存要比大多数人意识到的要复杂得多,如果你不确切知道自己在做什么,那么你就可以轻松地重新开发轮子并解决一些非常棘手的问题.
我推荐EHCache它是在Apache许可下.您需要查看EHCace代码示例.
选项#2:使用Squid
更容易解决您的问题的方法是使用Squid ...将Squid置于请求缓存数据的进程和发出请求的系统之间:http://www.squid-cache.org/