缓存(Caching)可以存储经常会用到的信息,这样每次需要的时候,这些信息都是立即可用的。在本章中,我们将会了解到Spring的缓存抽象。尽管Spring自身并没有实现缓存解决方案,但是它对缓存功能提供了声明式的支持,能够与多种流行的缓存实现进行集成。
Spring对缓存的支持有两种方式:
启用注解驱动的缓存:
Java配置:
@Configuration
@EnableCaching //启用缓存
public class CachingConfig {
//声明缓存管理器
@Bean
public CacheManager cacheManager(){
return new ConcurrentMapCacheManager();
}
}
XML配置:
id="cacheManager" class=
"org.springframework.cache.concurrent.ConcurrentMapCacheManager" />
本质上,@EnableCaching 和
的工作方式是相同的。他们都会创建一个切面并触发Spring缓存注解的切点。根据所使用的注解以及缓存的状态,这个切面会从缓存中获取数据,将数据添加到缓存之中或者从缓存中移除某一个值。
在上面的代码中,我们不仅启用了缓存,还配置了一个缓存管理器。缓存管理器是Spring缓存抽象的核心,它能够与多个流行的缓存实现进行集成。上面声明的ConcurrentMapCacheManager使用java.util.concurrent.ConcurrentHashMap作为其缓存存储。你猜的不错,它是基于内存的,所以它的声明周期是与应用关联的。对于生产级别的大型企业级应用程序,这可能并不是理想的选择。
下面,让我们看一下几个最为常用的缓存管理器。
Spring 3.1内置了五个缓存管理器的实现,如下所示:
除了核心的Spring框架,Spring Data又提供了两个缓存管理器:
使用Ehcache缓存:
Java配置:
@Configuration
@EnableCaching //启用缓存
public class CachingConfig {
//声明缓存管理器
@Bean
public EhCacheCacheManager cacheManager(CacheManager cm){
return new EhCacheCacheManager(cm);
}
@Bean
public EhCacheManagerFactoryBean ehcache(){
EhCacheManagerFactoryBean ehCacheFactoryBean = new EhCacheManagerFactoryBean();
ehCacheFactoryBean.setConfigLocation(
new ClassPathResource("cache/ehcache.xml"));
ehCacheFactoryBean.setShared(true);
return ehCacheFactoryBean;
}
}
ehcache.xml:
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
<cache name="testCache"
maxBytesLocalHeap="50m"
timeToLiveSeconds="100">
cache>
ehcache>
Spring和Ehcache都定义了CacheManager类型。需要明确的是,EhCache的CacheManager要被注入到Spring的EhCacheCacheManager(Spring CacheManager的实现)之中。除此之外,EhCache为XML定义了自己的配置模式,我们需要在一个XML文件中配置缓存,上面的ehcache.xml就是一个简单的配置:声明了一个名为testCache的缓存,它最大的堆存储为50MB,存活时间为100秒。
使用Redis缓存
后续补上
表中的所有注解都能运用在方法或类上。当将其放在单个方法上时,注解所描述的缓存行为只会运用到这个方法上。如果注解放在类级别的话,那么缓存行为就会应用到这个类的所有方法上。
注解 | 描述 |
---|---|
@Cacheable | 表明Spring在调用方法之前,首先应该在缓存中查找方法的返回值。如果这个值能够找到,就会返回缓存的值。否则的话,这个方法就会被调用,返回值会放到缓存之中 |
@CachePut | 表明Spring应该讲方法的返回值放到缓存中。在方法的调用前并不会检查缓存,方法始终都会被调用 |
@CacheEvict | 表明Spring应该在缓存中清楚一个或多个条目 |
@Caching | 这是一个分组的注解,能够同时应用多个其他的缓存注释 |
@Cacheable和@CachePut有一些共有的属性:
属性 | 类型 | 描述 |
---|---|---|
value | String[] | 要使用的缓存名称 |
condition | String | SpEL表达式,如果得到的值是false的话,不会将缓存应用到方法调用上 |
key | String | SpEL表达式,用来计算自定义的缓存key |
unless | String | SpEL表达式,如果得到的值是true的话,返回值不会放到缓存之中 |
示例:
@Cacheable("testCache")
public User findOne(int id){
System.out.println("findOne方法开始执行");
return this.sdjr.findOne(id);
}
@CachePut(value="testCache",key="#result.id")
public User save(User user){
System.out.println("save方法开始执行");
return this.sdjr.saveAndFlush(user);
}
key=”result.id”是一个自定义的缓存key,用的是SpEL表达式。
Spring提供了多个用来定义缓存规则的SpEL扩展:
表达式 | 描述 |
---|---|
#root.args |
传递给缓存方法的参数,形式为数组 |
#root.caches |
该方法执行时所对应的缓存,形式为数组 |
#root.target |
目标对象 |
#root.targetClass |
目标对象的类,是#root.target.class 的简写形式 |
#root.method |
缓存方法 |
#root.methodName |
缓存方法的名字,是#root.method.name 的简写形式 |
#result |
方法调用的返回值(不能用在@Cacheable注解上) |
#Argument |
任意的方法参数名(如#argName )或参数索引(如#a0 或#p0 ) |
@Cacheable和@CachePut提供了两个属性用以实现条件化缓存:unless和condition,这两个属性都接受一个SpEL表达式。它们之间有一点细微的差别。unless属性只能阻止将对象放进缓存,当它为true的时候,缓存方法返回的数据就不会放到缓存中。但是在这个方法调用的时候,依然会去缓存中进行查找,如果找到匹配的值,就会返回匹配的值。与之不同,如果condition的表达式计算结果为false,那么在这个方法调用的过程中,缓存是被禁用的。就是说,不会去缓存进行查找,同时返回值也不会放进缓存中。
@CacheEvict并不会往缓存中添加任何其他东西。相反,如果带有@CacheEvict注解的方法被调用的话,那么会有一个或更多的条目会在缓存中移除。
@CacheEvict注解的属性,指定了哪些缓存条目应该被移除掉
属性 | 类型 | 描述 |
---|---|---|
value | String[] | 要使用的缓存名称 |
key | String[] | SpEL表达式,用来计算自定义的缓存key |
condition | String | SpEL表达式,如果得到的值是false的话,缓存不会应用到方法调用上 |
allEntries | boolean | 如果为true的话,特定缓存的所有条目都会被移除掉 |
beforeInvocation | boolean | 如果为true的话,在方法调用之前移除条目。如果为false(默认值)的话,在方法成功调用之后再移除条目 |