简介

说明

Spring从3.1开始通过以下方法支持缓存:

  1. 定义了org.springframework.cache.Cache和org.springframework.cache.CacheManager接口来统一不同的缓存技术;
  1. CacheManager是Spring提供的各种缓存技术抽象接口,内部使用Cache接口进行缓存的增删改查操作,我们一般不会直接和Cache打交道。
  1. 支持使用JCache(JSR-107)注解简化我们开发;

缓存的逻辑 

        每次调用需要缓存功能的方法时,Spring会检查检查指定参数的指定的目标方法是否已经被调用过;

  1. 如果有:直接从缓存中获取方法调用后的结果
  2. 如果没有:调用方法并缓存结果后返回给用户。下次调用直接从缓存中获取。 

Cache的实现方式

        要使用Spring Boot的缓存功能,需要提供一个缓存的具体实现。

        可配置属性spring.cache.type强制指定缓存的实现。若不指定,则按顺序去侦测。

Spring Boot根据下面的顺序去侦测缓存实现:

  • Generic
  • JCache (JSR-107)
  • EhCache 2.x
  • Hazelcast
  • Infinispan
  • Redis
  • Guava
  • Simple

CacheManager实现类

针对不同的缓存技术,Spring有不同的CacheManager实现类,定义如下表:

CacheManager

描述

JCacheCacheManager

使用JCache(JSR-107)标准的实现作为缓存技术,比如Apache Commons JCS

EhCacheCacheManager

使用EhCache作为缓存技术

RedisCacheManager

使用Redis作为缓存技术

GuavaCacheManager

使用Google Guava的GuavaCache作为缓存技术

ConcurrentMapCacheManager

使用ConcurrentHashMap作为缓存技术(默认的方式

SimpleCacheManager

使用Collection作为缓存技术。主要用于测试

NoOpCacheManager

用于测试目的,事实上它并不缓存任何数据。

使用任意一个实现的CacheManager的时候,需要注册实现Bean:

// EhCache的配置
public EhCacheCacheManager cacheManager(CacheManager cacheManager) {
    return new EhCacheCacheManager(cacheManager);
}

使用

1.启用缓存功能

@EnableCaching:开启缓存功能。

package com.example.cache;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
 
@SpringBootApplication
@EnableCaching
public class SpringbootApplication{
 
    public static void main(String[] args) {
        SpringApplication.run(SpringbootApplication.class, args);
    }
}

2.指定缓存方式

见下方“指定缓存方式”

指定缓存方式

Redis

1.引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

        引入此依赖之后,SpringBoot会自动配置RedisCacheManager这个Bean(CacheManager的实现类),同时还会配置RedisTemplate这个Bean。 

当然,也可以手动提供bean,这样可以进行自定义的配置,覆盖默认配置:

@Configuration
public class RedisConfig extends CachingConfigurerSupport {

    // 自定义缓存key生成策略
    @Bean
    public KeyGenerator keyGenerator() {
        return new KeyGenerator() {
            @Override
            public Object generate(Object target, java.lang.reflect.Method method, Object... params) {
                StringBuffer sb = new StringBuffer();
                sb.append(target.getClass().getName());
                sb.append(method.getName());
                for (Object obj : params) {
                    sb.append(obj.toString());
                }
                return sb.toString();
            }
        };
    }

    // 缓存管理器
    @Bean
    public CacheManager cacheManager(@SuppressWarnings("rawtypes") RedisTemplate redisTemplate) {
        RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
        // 设置缓存过期时间(秒)
        cacheManager.setDefaultExpiration(3600);
        return cacheManager;
    }

    @Bean
    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
        StringRedisTemplate template = new StringRedisTemplate(factory);
        setSerializer(template);// 设置序列化工具
        template.afterPropertiesSet();
        return template;
    }

    private void setSerializer(StringRedisTemplate template) {
        @SuppressWarnings({ "rawtypes", "unchecked" })
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        template.setValueSerializer(jackson2JsonRedisSerializer);
    }
}

2.配置Redis信息

application.yml 

spring:
  redis:
    # Redis数据库索引(默认为0)
    database: 0
    # Redis服务器地址
    host: localhost
    # Redis服务器连接端口
    port: 6379
    # Redis服务器密码
    password: 123456
    pool:
      # 连接池最大连接数(使用负值表示没有限制)
      max-active: 8
      # 连接池最大阻塞等待时间(使用负值表示没有限制)
      max-wait: -1
      # 连接池中的最大空闲连接
      max-idle: 8
      # 连接池中的最小空闲连接
      min-idle: 0
    # 连接超时时间(毫秒)
    timeout: 0

Guava

1.引入依赖

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>18.0</version>
</dependency>

引入此依赖之后,SpringBoot会为我们自动配置GuavaCacheManager这个Bean。 

Ehcache

1.引入依赖

<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcahe</artifactId>
</dependency>

2.配置文件(可以不配置)

application.yml 

默认就是下边这个路径,ehcache.xml必须有。

spring:
  cache:
    ehcache:
      config: classpath:/ehcache.xml

3.ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false" monitoring="autodetect"
         dynamicConfig="true">

    <diskStore path="java.io.tmpdir/ehcache"/>

    <defaultCache
            maxElementsInMemory="50000"
            eternal="false"
            timeToIdleSeconds="3600"
            timeToLiveSeconds="3600"
            overflowToDisk="true"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
    />

    <cache name="authorizationCache"
           maxEntriesLocalHeap="2000"
           eternal="false"
           timeToIdleSeconds="3600"
           timeToLiveSeconds="3600"
           overflowToDisk="false"
           statistics="true">
    </cache>
</ehcache>

diskStore节点

磁盘存储:将缓存中暂时不使用的对象,转移到硬盘,类似于Windows系统的虚拟内存 path:指定在硬盘上存储对象的路径 path可以配置的目录有: user.home(用户的家目录) user.dir(用户当前的工作目录) java.io.tmpdir(默认的临时目录) ehcache.disk.store.dir(ehcache的配置目录) 绝对路径(如:d:\\ehcache) 查看路径方法:String tmpDir = System.getProperty("java.io.tmpdir");

defaultCache

默认的缓存配置信息,如果不加特殊说明,则所有对象按照此配置项处理。

  • axElementsInMemory:设置了缓存的上限,最多存储多少个记录对象
  • eternal:代表对象是否永不过期 (指定true则下面两项配置需为0无限期)
  • timeToIdleSeconds:最大的发呆时间 /秒
  • timeToLiveSeconds;最大的存活时间 /秒
  • overflowToDisk:是否允许对象被写入到磁盘

说明:示例中的配置自缓存建立起600秒(10分钟)有效 。 在有效的600秒(10分钟)内,如果连续120秒(2分钟)未访问缓存,则缓存失效。 就算有访问,也只会存活600秒。

ConcurrentHashMap

Spring boot默认使用ConcurrentMapCacheManager来管理缓存(内部使用ConcurrentHashMap)。

所以,只在启动类加注解即可:@EnableCaching