Spring 集成缓存

Spring 中提供了缓存功能的抽象,允许你在底层灵活的替换缓存实现,而对上层暴露相同的缓存接口。

缓存接口

Spring 的缓存 API 以注解方式提供。

开启注解

Spring 为缓存功能提供了注解功能,但是你必须启动注解。你有两个选择:(1) 在 xml 中声明像上一节 spring-ehcache.xml 中的做法一样,使用<cache:annotation-driven/>

  1. <cache:annotation-driven cache-manager="cacheManager"/>

(2) 使用标记注解你也可以通过对一个类进行注解修饰的方式在这个类中使用缓存注解。范例如下:

  1. @Configuration
  2. @EnableCaching
  3. public class AppConfig {
  4. }

缓存注解使用

Spring 对缓存的支持类似于对事务的支持。首先使用注解标记方法,相当于定义了切点,然后使用 Aop 技术在这个方法的调用前、调用后获取方法的入参和返回值,进而实现了缓存的逻辑。下面三个注解都是方法级别:

@Cacheable

表明所修饰的方法是可以缓存的:当第一次调用这个方法时,它的结果会被缓存下来,在缓存的有效时间内,以后访问这个方法都直接返回缓存结果,不再执行方法中的代码段。这个注解可以用condition属性来设置条件,如果不满足条件,就不使用缓存能力,直接执行方法。可以使用key属性来指定 key 的生成规则。

@CachePut

@Cacheable不同,@CachePut不仅会缓存方法的结果,还会执行方法的代码段。它支持的属性和用法都与@Cacheable一致。

@CacheEvict

@Cacheable功能相反,@CacheEvict表明所修饰的方法是用来删除失效或无用的缓存数据。下面是@Cacheable@CacheEvict@CachePut基本使用方法的一个集中展示:

  1. @Service
  2. public class UserService {
  3. // @Cacheable可以设置多个缓存,形式如:@Cacheable({"books", "isbns"})
  4. @Cacheable(value={"users"}, key="#user.id")
  5. public User findUser(User user) {
  6. return findUserInDB(user.getId());
  7. }
  8. @Cacheable(value = "users", condition = "#user.getId() <= 2")
  9. public User findUserInLimit(User user) {
  10. return findUserInDB(user.getId());
  11. }
  12. @CachePut(value = "users", key = "#user.getId()")
  13. public void updateUser(User user) {
  14. updateUserInDB(user);
  15. }
  16. @CacheEvict(value = "users")
  17. public void removeUser(User user) {
  18. removeUserInDB(user.getId());
  19. }
  20. @CacheEvict(value = "users", allEntries = true)
  21. public void clear() {
  22. removeAllInDB();
  23. }
  24. }

@Caching

如果需要使用同一个缓存注解(@Cacheable@CacheEvict@CachePut)多次修饰一个方法,就需要用到@Caching

  1. @Caching(evict = { @CacheEvict("primary"), @CacheEvict(cacheNames="secondary", key="#p0") })
  2. public Book importBooks(String deposit, Date date)

@CacheConfig

与前面的缓存注解不同,这是一个类级别的注解。如果类的所有操作都是缓存操作,你可以使用@CacheConfig来指定类,省去一些配置。

  1. @CacheConfig("books")
  2. public class BookRepositoryImpl implements BookRepository {
  3. @Cacheable
  4. public Book findBook(ISBN isbn) {...}
  5. }

缓存存储

Spring 允许通过配置方式接入多种不同的缓存存储。用户可以根据实际需要选择。

不同的缓存存储,具有不同的性能和特性,如果想了解具体原理,可以参考:全面理解缓存原理。这里不再赘述。

使用 ConcurrentHashMap 作为缓存

参考配置:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xmlns:cache="http://www.springframework.org/schema/cache" xmlns:p="http://www.springframework.org/schema/p"
  6. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  7. http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
  8. http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
  9. <description>使用 ConcurrentHashMap 作为 Spring 缓存</description>
  10. <!--配置参考:https://docs.spring.io/spring/docs/current/spring-framework-reference/integration.html#cache-store-configuration-->
  11. <context:component-scan base-package="io.github.dunwu.spring.cache"/>
  12. <bean id="simpleCacheManager" class="org.springframework.cache.support.SimpleCacheManager">
  13. <property name="caches">
  14. <set>
  15. <bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="default"/>
  16. <bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="users"/>
  17. </set>
  18. </property>
  19. </bean>
  20. <cache:annotation-driven cache-manager="simpleCacheManager"/>
  21. </beans>

使用 Ehcache 作为缓存

参考配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:cache="http://www.springframework.org/schema/cache"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
         http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
         http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">

  <description>使用 EhCache 作为 Spring 缓存</description>

  <!--配置参考:https://docs.spring.io/spring/docs/current/spring-framework-reference/integration.html#cache-store-configuration-->

  <context:component-scan base-package="io.github.dunwu.spring.cache"/>

  <bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
    <property name="configLocation" value="classpath:ehcache/ehcache.xml"/>
  </bean>

  <bean id="ehcacheCacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
    <property name="cacheManager" ref="ehcache"/>
  </bean>

  <cache:annotation-driven cache-manager="ehcacheCacheManager"/>
</beans>

ehcache.xml 中的配置内容完全符合 Ehcache 的官方配置标准。

使用 Caffeine 作为缓存

参考配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:cache="http://www.springframework.org/schema/cache"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
         http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
         http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">

  <description>使用 Caffeine 作为 Spring 缓存</description>

  <!--配置参考:https://docs.spring.io/spring/docs/current/spring-framework-reference/integration.html#cache-store-configuration-->

  <context:component-scan base-package="io.github.dunwu.spring.cache"/>

  <bean id="caffeineCacheManager" class="org.springframework.cache.caffeine.CaffeineCacheManager"/>

  <cache:annotation-driven cache-manager="caffeineCacheManager"/>
</beans>

示例代码

我的示例代码地址:spring-tutorial-integration-cache

参考资料