SimpleCacheManager
NoOpCacheManager
ConcurrentMapCacheManager
CompositeCacheManager
EhCacheCacheManager
RedisCacheManager(来自于Spring Data Redis项目)
GemfireCacheManager(来自于Spring Data GemFire项目)
EhCacheCacheManager
我们需要使用EhCache的CacheManager来进行注入, 所以必须也要声明一个CacheManager bean。 为了对其进行简化, Spring提供了EhCacheManagerFactoryBean来生成EhCache的CacheManager。 方法ehcache()会创建并返回一个EhCacheManagerFactoryBean实例。 因为它是一个工厂bean(也就是说, 它实现了Spring的FactoryBean接口) , 所以注册在Spring应用上下文中的并不是EhCacheManagerFactoryBean的实例, 而是CacheManager的一个实例, 因此适合注入到EhCacheCacheManager之中。
除了在Spring中配置的bean, 还需要有针对EhCache的配置。 EhCache为XML定义了自己的配置模式, 我们需要在一个XML文件中配置缓存,该文件需要符合EhCache所定义的模式。 在创建EhCacheManagerFactoryBean的过程中, 需要告诉它EhCache配置文件在什么地方。 在这里通过调用setConfigLocation()方法, 传入ClassPath-Resource, 用来指明EhCache XML配置文件相对于根类路径(classpath) 的位置。至于ehcache.xml文件的内容, 不同的应用之间会有所差别, 但是至少需要声明一个最小的缓存。 例如, 如下的EhCache配置声明一个名为spittleCache的缓存, 它最大的堆存储为50MB, 存活时间为100秒。
为了使用RedisCacheManager, 我们需要RedisTemplate bean以及RedisConnectionFactory实现类(如JedisConnectionFactory) 的一个bean。在之前配置RedisTemplate、RedisConnectionFactory的基础上配置RedisCacheManager:
CompositeCacheManager要通过一个或更多的缓存管理器来进行配置, 它会迭代这些缓存管理器, 以查找之前所缓存的值。 以下的程序清
注 解 | 描 述 |
@Cacheable | 表明Spring在调用方法之前, 首先应该在缓存中查找方法的返回值。 如果这个值能够找到, 就会返回缓存的值。 否则的话, 这个方法就会被调用, 返回值会 放到缓存之中 |
@CachePut | 表明Spring应该将方法的返回值放到缓存中。 在方法的调用前并不会检查缓存, 方法始终都会被调用 |
@CacheEvict | 表明Spring应该在缓存中清除一个或多个条目 |
@Caching | 这是一个分组的注解, 能够同时应用多个其他的缓存注解 |
@Cacheable首先在缓存中查找条目, 如果找到了匹配的条目, 那么就不会对方法进行调用了。 如果没有找到匹配的条目, 方法会被调用并且返回值要放到缓存之中。 而@CachePut并不会在缓存中检查匹配的值, 目标方法总是会被调用, 并将返回值添加到缓存之中。
@Cacheable和@CachePut有一些属性是共有的:
属 性 | 类 型 | 描 述 |
value | String[] | 要使用的缓存名称 |
condition | String | SpEL表达式, 如果得到的值是false的话, 不会将缓存应用到方法调用上 |
key | String | SpEL表达式, 用来计算自定义的缓存key |
unless | String | SpEL表达式, 如果得到的值是true的话, 返回值不会放到缓存之中 |
在最简单的情况下, 在@Cacheable和@CachePut的这些属性中, 只需使用value属性指定一个或多个缓存即可。 例如, SpittleRepository的findOne()方法。 在初始保存之后, Spittle就不会再发生变化了。 通过在findOne()方法上添加@Cacheable注解,能够确保将Spittle保存在缓存中, 从而避免对数据库的不必要访问。
@Cacheable会条件性地触发对方法的调用, 这取决于缓存中是不是已经有了所需要的值, 对于所注解的方法, @CachePut采用了一种更为直接的流程。 带有@CachePut注解的方法始终都会被调用, 而且它的返回值也会放到缓存中。 这提供一种很便利的机制, 能够让我们在请求之前预先加载缓存。
例如, 当一个全新的Spittle通过SpittleRepository的save()方法保存之后, 很可能马上就会请求这条记录。 所以, 当save()方法调用后, 立即将Spittle塞到缓存之中是很有意义的, 这样当其他人通过findOne()对其进行查找时, 它就已经准备就绪了。 为了实现这一点, 可以在save()方法上添加@CachePut注解, 如下所示:
表 达 式 | 描 述 |
#root.args | 传递给缓存方法的参数, 形式为数组 |
#root.caches | 该方法执行时所对应的缓存, 形式为数组 |
#root.target | 目标对象 |
#root.targetClass | 目标对象的类, 是#root.target.class的简写形式 |
#root.method | 缓存方法 |
#root.methodName | 缓存方法的名字, 是#root.method.name的简写形式 |
#result | 方法调用的返回值(不能用在@Cacheable注解上) |
#Argument | 任意的方法参数名(如#argName) 或参数索引(如#a0或#p0) |
表达式#result能够得到返回的Spittle。 借助这个对象, 我们可以通过将key属性设置为#result.id来引用id属性 :
属 性 | 类 型 | 描 述 |
value | String [] | 要使用的缓存名称 |
key | String | SpEL表达式, 用来计算自定义的缓存key |
condition | String | SpEL表达式, 如果得到的值是false的话, 缓存不会应用到方法调用上 |
allEntries | b oolean | 如果为true的话, 特定缓存的所有条目都会被移除掉 |
beforeInvocation | b oolean | 如果为true的话, 在方法调用之前移除条目。 如果为false(默认值) 的话, 在方法成功调用之后再移除条目 |
元素 | 描述 |
<cache:annotation-driven> | 启用注解驱动的缓存。 等同于Java配置中的@EnableCaching |
<cache:advice> | 定义缓存通知(advice) 。 结合<aop:advisor>, 将通知应用到切点上 |
<cache:caching> | 在缓存通知中, 定义一组特定的缓存规则 |
<cache:cacheable> | 指明某个方法要进行缓存。 等同于@Cacheable注解 |
<cache:cache-put> | 指明某个方法要填充缓存, 但不会考虑缓存中是否已有匹配的值。 等同于@CachePut注解 |
<cache:cache-evict> | 指明某个方法要从缓存中移除一个或多个条目, 等同于@CacheEvict注解 |