Spring Cache是对缓存使用的抽象,通过它我们可以在不侵入业务代码的基础上让现有代码即刻支持缓存。为现有的Spring 应用添加Cache非常简单,为了启用缓存,Spring充分利用了注释,就像启用框架中的任何其他配置级功能一样。
只需将@EnableCaching注解添加到任何配置类,即可以声明方式启用高速缓存功能:
@Configuration
@EnableCaching
public class CachingConfig {
@Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager("addresses");
}
}
当然,您也可以使用XML配置启用缓存管理:
注意:在我们启用缓存之后 - 为了最小化设置 - 我们必须注册一个cacheManager。
使用XML可以使用更灵活的选项来配置缓存 - 您可以指定自己的缓存管理器,缓存解析器,错误处理程序,并且通常使用更高级的自定义选项。
一旦启用了缓存,下一步就是将缓存行为绑定到具有声明性注解的方法。
为方法启用缓存行为的最简单方法是使用@Cacheable对其进行声明,使用将存储结果的缓存名称对其进行参数化:
@Cacheable("addresses")
public String getAddress(Customer customer) {...}
方法被调用时,先从缓存中读取数据,如果缓存没有找到数据,再调用方法获取数据,然后把数据添加到缓存中
缓存可以变得非常大,我们可能会持续存储大量过时或未使用的数据。
@CacheEvict注解用于去除一个、多个或所有的缓存值-让新鲜值可以重新加载到缓存中:
@CacheEvict(value="addresses", allEntries=true)
public String getAddress(Customer customer) {...}
在这里,我们将附加参数allEntries与要清空的缓存结合使用 - 清除缓存地址中的所有条目并为新数据做好准备。
虽然@CacheEvict通过删除过时和未使用的条目来减少在大型缓存中查找条目的开销,但有些情况下,您希望避免从缓存中驱逐太多数据。您需要在更改条目时有选择地智能地更新条目。
使用@CachePut,您可以更新缓存的内容,而不会干扰方法执行。也就是说,调用方法时会自动把相应的数据放入缓存。
@CachePut(value="addresses")
public String getAddress(Customer customer) {...}
如果要使用相同类型的多个注解来缓存方法,该怎么办?看下面的例子:
@CacheEvict("addresses")
@CacheEvict(value="directory", key=customer.name)
public String getAddress(Customer customer) {...}
上面的代码将无法编译,因为Java不允许为给定方法声明相同类型的多个注解。
上述问题的解决方法是:
@Caching(evict = {
@CacheEvict("addresses"),
@CacheEvict(value="directory", key="#customer.name") })
public String getAddress(Customer customer) {...}
如上面的代码片段所示,您可以使用@Caching对多个缓存进行分组,并使用它来实现您自己的自定义缓存逻辑。
使用@CacheConfig注解,您可以将一些缓存配置简化在类级别上 - 这样您就不必多次声明:
@CacheConfig(cacheNames={"addresses"})
public class CustomerDataService {
@Cacheable
public String getAddress(Customer customer) {...}
如果我们想要更多地控制注解何时处于活动状态,比如可以使用条件参数对@CachePut进行参数化,该参数采用SpEL表达式来缓存结果:
@CachePut(value="addresses", condition="#customer.name=='Tom'")
public String getAddress(Customer customer) {...}
我们还可以根据方法的输出而不是输入来控制缓存- 通过unless参数:
@CachePut(value="addresses", unless="#result.length()<64")
public String getAddress(Customer customer) {...}
上述代码将缓存addresses,除非它们长度小于64个字符。
在本文中,我们讨论了Spring中缓存的基础知识以及如何通过注解来充分利用该抽象。