在使用 Spring Framework 构建的 Java EE 应用程序中,我需要在 DAO 中执行一些非常昂贵的操作,这可能需要几分钟时间。使用 Spring MVC,当用户的请求映射到控制器方法时,我通过控制器访问 DAO:
@RequestMapping(value = "/categories.do")
public ModelAndView categories(
@PathVariable("cc") String cc,
@PathVariable("ll") String ll) {
Locale locale = new Locale(ll, cc);
ModelAndView result = getView("categories", locale);
Map<Category, List<Product>> allProducts = supplyDao.getAllProducts(locale);
result.addObject("products", allProducts);
return result;
}
该getAllProducts
方法向外部 Web 服务发出大量请求,以获取产品所需的所有数据。该方法通过 Spring 的@Cacheable
注解缓存在底层Ehcache
实现上:
@Cacheable(value = CACHE_NAME, key = CACHE_KEY_PREFIX + "'(' + #p0 + ')'")
public Map<Category, List<Product>> getAllProducts(Locale locale) {
// a lot of HTTP requests firing from here
}
这种方法的问题是,当缓存为空时,页面基本上是不可访问的。此外,如果在缓存为空时有多个请求命中页面,DAO 方法将再次触发,所有请求将并行重复。据我了解,第二个问题的解决方案是使用 a BlockingCache
,但我还没有机会实现它。
我想要的是让控制器方法总是从缓存中提取结果。我想实现一种@PostConstruct
触发所有语言环境的缓存填充的方法。就像是:
@PostConstruct
public void populateCaches() {
for (Locale locale : localeList) {
getAllProducts(locale);
}
}
我不介意初始填充需要一段时间,因为服务器很少重新启动。我还将缓存过期时间设置为三天 - 数据不会经常更新,并且不提供最新版本没有危险。
我想做的是按TimerTask
设定的时间间隔运行 a,比如说两天 23 小时,这将迫使 DAO 方法从 Web 服务中提取所有产品数据。然后,此数据将替换缓存中的数据,而不会过期。然后将重置缓存过期计数器 - 数据将在三天后再次过期。这样,控制器方法将始终从缓存中获取产品数据,并且页面将响应。
我的问题是,鉴于我正在使用Spring 的缓存抽象,我将如何实现这样的方法?我需要CacheManager
直接在我的方法中处理吗?
另一个问题是:我是否正确地解决了这个问题?有没有更好的方法来做到这一点?