Spring的@Cacheable注释是否与注释方法的bean具有相同的范围?

时间:2012-04-14 04:50:27

标签: java spring

是否有一种简单的方法可以将Spring的@Cacheable注释与非单例(例如会话范围的)bean一起使用,并使缓存与所述bean具有相同的范围?

示例:

import javax.inject.Inject;
import javax.inject.Named;

import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Scope;
import org.springframework.security.core.context.SecurityContextHolder;

@Named
@Scope("session")
public class UserNameRetriever {

    @Inject private UserDao userDao;

    @Cacheable("userName")
    public String getUserName() {
        return userDao.getUserByLogin((String)SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getName();
    }

}

理想情况下,UserNameRetriever.getUserName()会在每个会话中从UserDao获取一次用户名,但此代码实际上会缓存整个应用程序范围。

3 个答案:

答案 0 :(得分:4)

如果您想要会话缓存,请使用会话。也就是说,将用户存储在会话范围的bean中的私有字段中,或直接访问HttpSession对象。 @Cacheable通常用于应用程序范围的资源。

好吧,您可以使用key="#user.id",并使用@CacheEvict方法使缓存无效(手动或使用@PreDestroy),但如果不混合使用会更好两个 - 缓存和会话数据。

答案 1 :(得分:2)

我认为你正在从错误的一方接近这个问题。而不是只有“本地”会话范围的缓存只存储一个值,而是有一个全局缓存存储从用户名到User值的映射。

在你的情况下,在@Cacheable上放getUserName()并将其放在UserDao上:

public class UserDao {
  @Cacheable("users")
  public User getUserByLogin(String user) {
    //...
  }
}

不仅这是对缓存的更惯用的使用,而且它将更容易维护和更好的执行。

回到原来的问题:不,这不可能是开箱即用的。您必须在现有实施中编写自己的CacheManager - 可能是

答案 2 :(得分:2)

我没有尝试过,但根据Spring reference我觉得这样可行:

@Cacheable(value = "userName", key = "#root.target")