7

是否有一种简单的方法可以将 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每个会话一次中获取用户名,但此代码实际上在应用程序范围内缓存。

4

3 回答 3

5

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

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

于 2012-04-14T21:11:56.277 回答
2

我认为你是从错误的角度来解决问题的。不是让“本地”会话范围的缓存只存储一个值,而是使用一个全局缓存来存储从用户名到User值的映射。

在你的情况下@CacheablegetUserName()把它放在UserDao

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

这不仅是缓存的更惯用用法,而且事实证明它更容易维护和更好地执行。

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

于 2012-04-14T08:25:26.447 回答
1

我还没有尝试过,但根据Spring 参考我认为这会起作用:

@Cacheable(value = "userName", key = "#root.target")
于 2012-04-14T12:19:00.787 回答