Spring Cache
第一步:配置缓存管理
<context:component-scan base-package="com.hef"/>
<cache:annotation-driven/>
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="default"/>
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="users"/>
set>
property>
bean>
第二步:使用缓存
@Cacheable(cacheNames = "users")
@Override
public User getUserById(String userId) {
System.out.println("real query user." + userId);
return getFromDB(userId);
}
private User getFromDB(String userId){
System.out.println("real querying db..." + userId);
return new User.Builder().userId(userId).email("[email protected]").builder();
}
只有使用public定义的方法才可以被缓存。
缓存的本质就是键/值对集合。在默认情况下,缓存抽象使用方法签名及参数值作为一个键值,并将该键与方法调用的结果组成键/值对。
@Cacheable
Spring首先在缓存中查找数据,如果没有则执行方法并缓存结果,然后返回数据
缓存名必须提供;可以使用引号、Value或者cacheNames属性来定义名称
@Cacheable(cacheNames = "users")
@Cacheable(values = "users")
@Cacheable(cacheNames = {"cache01","cache02"})
键生成器
默认情况下,缓存抽象使用方法签名及参数值作为一个键值,并将键与方法调用的结果组成键/值对。
1)可以使用SpEL指定自定义键
@Cacheable(cacheNames = "users", key = "#user.userCode")
public User getUserByUser(User user) {
System.out.println("real query user." + user.getUserCode());
return getFromDB(user.getUserId());
}
2)可以通过实现org.springframework.cache.interceptor.KeyGenerator
接口来定义个性化的Key生成器
@Cacheable(cacheNames = "users", keyGenerator = "myKeyGenerator")
3)带条件缓存
@Cacheable(cacheNames = "users", key = "#user.userCode", condition = "#user.age >= 12")
@CachePut
首先执行方法,然后将返回值放入缓存。当希望使用方法返回值更新缓存时,便可以选择这种方法。
####(3)@CacheEvict
负责从给定的缓存中移除一个值。
默认情况下,@CacheEvict
注解在方法调用之后运行。
@allEntries
属性 定义了是否移除缓存的所有条目,默认不移除这些条目;@beforeInvocation
属性定义了在调用方法之前还是之后完成移除操作。
@CacheEvict(cacheNames = "users", allEntries = true, beforeInvocation = true)
@Caching
@Caching
是一个组注解,可以为一个方法定义提供基于@Cacheable
、@CacheEvict
、@CachePut
注解的数组
@Caching(cacheable = {@Cacheable(value = "members", condition = "#obj instanceof T(com.hef.domain.Member)"),
@Cacheable(value = "visitors", condition = "#obj instanceof T(com.hef.domain.Visitor)")})
@CacheConfig
类级别的缓存如果一个类中需要缓存的方法注解属性都相似,可以在类上通过@CacheConfig
配置缓存,在方法上用@Cacheable
标记。
基于Proxy的Spring AOP带来的内部调用问题。
如果对象的方法是内部调用(this)而不是外部引用,则会导致代理失效,那么切面就失效,也就是说上面定义的各种注解,包括@Cacheable、@CachePut、@CacheEvict
都会失效
public User getUserByUser02(User user) {
return getUserByUser(user);
}
@Cacheable(cacheNames = "users", key = "#user.userCode")
public User getUserByUser(User user) {
System.out.println("real query user." + user.getUserCode());
return getFromDB(user.getUserId());
}
在方法getUserByUser02()
上调用getUserByUser()
,发生了内部调用(this),所以没有使用代理类,导致Spring Cache失效。要避免这个问题,就要避免方法的内部调用,或者避免使用基于代理的AOP模式,也可以使用基于AspectJ的AOP模式来解决这个问题。