springboot的缓存

Spring缓存注解

最常用的缓存注解有如下:

  • @Cacheable主要针对方法配置,能够根据方法的请求参数对其结果进行缓存。
  • @CacheEvict清空缓存。用于标注在一些删除方法上。
  • @CachePut保证方法被调用,又希望结果被缓存。用于标注在一些更新方法上,更新缓存。
  • @EnableCaching开启基于注解的缓存。
	@Cacheable("CACHE-DistrictProvince")
	public List<DistrictProvinceVO> listProvinceByCache() {
		省略...
	}
	// 把缓存名称为【CACHE-DistrictProvince】下面的对象都清除
	@CacheEvict(value = "CACHE-DistrictProvince", allEntries = true)
	public void clean() {
	}
	
	// 
	@Cacheable(value = "CACHE-DistrictCity", key = "#param['provinceId']")
	public List<DistrictCityVO> listCityByCache(Map<String, Object> param) {
		省略...
	}
	// 把缓存名称为【CACHE-DistrictCity】下面的对象key为provinceId的对象清除
	@CacheEvict(value = "CACHE-DistrictCity", key = "#provinceId")
	public void clean(String provinceId) {
	}

spring支持的缓存

org.springframework.boot.autoconfigure.cache.CacheType 定义了几种spring缓存类型

public enum CacheType {
	GENERIC,
	JCACHE,
	EHCACHE,
	HAZELCAST,
	INFINISPAN,
	COUCHBASE,
	REDIS,
	CAFFEINE,
	SIMPLE,
	NONE
}

spring配置文件通过 spring.cache.type=redis 来确定使用哪个缓存
这个类也可以对具体的缓存类型指定更多的缓存配置

@ConfigurationProperties(prefix = "spring.cache")
public class CacheProperties {
	private CacheType type;
	private List<String> cacheNames = new ArrayList<>();
	private final Caffeine caffeine = new Caffeine();
	private final Couchbase couchbase = new Couchbase();
	private final EhCache ehcache = new EhCache();
	private final Infinispan infinispan = new Infinispan();
	private final JCache jcache = new JCache();
	private final Redis redis = new Redis();
}

spring的默认缓存

只需依赖spring-boot-starter-cache就可以使用spring默认的cache
在这里插入图片描述

依赖

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

默认缓存示例

在这里插入图片描述

@EnableCaching启用spring缓存

@SpringBootApplication
@EnableCaching
public class SpringbootCacheApplication {
	public static void main(String[] args) {
		SpringApplication.run(SpringbootCacheApplication.class, args);
	}
}
@Slf4j
@SpringBootTest(classes=SpringbootCacheApplication.class)
@RunWith(SpringRunner.class)
class CacheDemoServiceTest {
	@Autowired CacheManager cacheManager;
	@Autowired CacheDemoService cacheDemoService;
	@Test
	void test() {
		// 打印CacheManager的真实对象
		log.info("CacheManager={}", cacheManager.getClass().getSimpleName());
	}
	@Test
	void test1() {
		String code = "99";
		log.info("cacheNames={}", cacheManager.getCacheNames());
		log.info("testCache={}", cacheDemoService.testCache(code));
		log.info("cacheNames={}", cacheManager.getCacheNames());
		log.info("testCache={}", cacheDemoService.testCache(code));
	}
}
public interface CacheDemoService {
	List<String> testCache(String code);
}
@Service
@Slf4j
public class CacheDemoServiceImpl implements CacheDemoService {
	@Override
	@Cacheable(cacheNames = "demo", key="#code")
	public List<String> testCache(String code) {
		log.info("执行方法 CacheDemoServiceImpl.testCache ... ");
		return Arrays.asList("1","2");
	}
}

打印测试信息

第一次执行,因为没有缓存,正常调用service方法
spring的默认cache是 org.springframework.cache.concurrent.ConcurrentMapCacheManager

2022-05-15 21:17:59.438  INFO 13984 --- [           main] z.l.s.service.CacheDemoServiceTest       : CacheManager=ConcurrentMapCacheManager
2022-05-15 21:17:59.452  INFO 13984 --- [           main] z.l.s.service.CacheDemoServiceTest       : cacheNames=[]
2022-05-15 21:17:59.486  INFO 13984 --- [           main] z.l.s.service.impl.CacheDemoServiceImpl  : 执行方法 CacheDemoServiceImpl.testCache ... 
2022-05-15 21:17:59.486  INFO 13984 --- [           main] z.l.s.service.CacheDemoServiceTest       : testCache=[1, 2]
2022-05-15 21:17:59.486  INFO 13984 --- [           main] z.l.s.service.CacheDemoServiceTest       : cacheNames=[demo]
2022-05-15 21:17:59.487  INFO 13984 --- [           main] z.l.s.service.CacheDemoServiceTest       : testCache=[1, 2]

第二次执行,这时候因为有了对应的缓存,不在执行service中的方法,直接返回缓存中的值
往后再执行,打印信息与第二次的一样。

spring默认缓存配置原理

spring-boot-autoconfigure.jar 中有一个配置类SimpleCacheConfiguration
如果应用缺少CacheManager对象,那么实例化一个ConcurrentMapCacheManager 对象
ConcurrentMapCacheManager就是CacheManager的一个实现
ConcurrentMapCacheManager和CacheManager都在 spring-context.jar中

@Configuration
@ConditionalOnMissingBean(CacheManager.class)
@Conditional(CacheCondition.class)
class SimpleCacheConfiguration {
	@Bean
	public ConcurrentMapCacheManager cacheManager() {
		ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager();
		List<String> cacheNames = this.cacheProperties.getCacheNames();
		if (!cacheNames.isEmpty()) {
			cacheManager.setCacheNames(cacheNames);
		}
		return this.customizerInvoker.customize(cacheManager);
	}
}

spring整合EhCache

依赖

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-cache</artifactId>
		</dependency>		
		<dependency>
			<groupId>net.sf.ehcache</groupId>
			<artifactId>ehcache</artifactId>
		</dependency>

在这里插入图片描述

application.properties

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

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">
	<!-- 磁盘缓存位置 -->
	<diskStore path="java.io.tmpdir" />
	<!-- 默认缓存 -->
	<defaultCache 
		maxElementsInMemory="10000" 
		eternal="false"
		timeToIdleSeconds="120" 
		timeToLiveSeconds="120" 
		maxElementsOnDisk="10000000"
		diskExpiryThreadIntervalSeconds="120" 
		memoryStoreEvictionPolicy="LRU">
		<persistence strategy="localTempSwap" />
	</defaultCache>
	<!-- 测试 -->
	<cache name="demo" 
		eternal="false" 
		timeToIdleSeconds="2400"
		timeToLiveSeconds="2400" 
		maxEntriesLocalHeap="10000"
		maxEntriesLocalDisk="10000000" 
		diskExpiryThreadIntervalSeconds="120"
		overflowToDisk="false" 
		memoryStoreEvictionPolicy="LRU">
	</cache>
</ehcache>

缓存配置:

timeToIdleSeconds 当缓存闲置n秒后销毁
timeToLiveSeconds 当缓存存活n秒后销毁

  • name:缓存名称。
  • maxElementsInMemory:缓存最大个数。
  • eternal:对象是否永久有效,一但设置了,timeout将不起作用。
  • timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
  • timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
  • overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。
  • diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
  • maxElementsOnDisk:硬盘最大缓存个数。
  • diskPersistent:是否缓存虚拟机重启期数据
    Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
  • diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。 memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是 LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
  • clearOnFlush:内存数量最大时是否清除

EhCache示例

EhCache示例直接使用原先的示例,不需修改

打印测试信息

第一次执行,因为没有缓存,正常调用service方法
因为在ehcache.xml配置了cache示例(name=demo),所以初次调用可以获取cacheName

执行方法 CacheController.testCache ... 
CacheManager=org.springframework.cache.ehcache.EhCacheCacheManager
cacheManager.getCacheNames()=[demo]
执行方法 CacheDemoServiceImpl.testCache ... 

第二次执行,这时候因为有了对应的缓存,不在执行service中的方法,直接返回缓存中的值
往后再执行,打印信息与第二次的一样。

执行方法 CacheController.testCache ... 
CacheManager=org.springframework.cache.ehcache.EhCacheCacheManager
cacheManager.getCacheNames()=[demo]

spring中Ehcache缓存配置原理

spring-boot-autoconfigure.jar 中有一个配置类EhCacheCacheConfiguration
如果应用包含Cache.classEhCacheCacheManager.class缺少CacheManager对象,
那么配置文件EhCacheCacheConfiguration 生效,然后会实例化一个EhCacheCacheManager 对象

@Configuration
@ConditionalOnClass({ Cache.class, EhCacheCacheManager.class })
@ConditionalOnMissingBean(org.springframework.cache.CacheManager.class)
@Conditional({ CacheCondition.class,
		EhCacheCacheConfiguration.ConfigAvailableCondition.class })
class EhCacheCacheConfiguration {
	@Bean
	public EhCacheCacheManager cacheManager(CacheManager ehCacheCacheManager) {
		return this.customizers.customize(new EhCacheCacheManager(ehCacheCacheManager));
	}
	@Bean
	@ConditionalOnMissingBean
	public CacheManager ehCacheCacheManager() {
		Resource location = this.cacheProperties.resolveConfigLocation(this.cacheProperties.getEhcache().getConfig());
		if (location != null) {
			return EhCacheManagerUtils.buildCacheManager(location);
		}
		return EhCacheManagerUtils.buildCacheManager();
	}
}

EhCacheCacheManagerspring-context-support.jar
在这里插入图片描述

spring整合redis

依赖

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

application.properties

CacheProperties下面的Redis配置缓存信息
org.springframework.boot.autoconfigure.cache.CacheProperties

public static class Redis {
//redis过期时间,默认不过期
		private Duration timeToLive;
		// 允许 null 值
		private boolean cacheNullValues = true;
		// 给Key加前缀
		private String keyPrefix;
		// 是否使用前缀
		private boolean useKeyPrefix = true;
		// 允许统计
		private boolean enableStatistics;
}

配置RedisProperties
org.springframework.boot.autoconfigure.data.redis.RedisProperties

@ConfigurationProperties(prefix = "spring.redis")
public class RedisProperties {
	private int database = 0;
	private String url;
	private String host = "localhost";
	private String username;
	private String password;
	private int port = 6379;
	private boolean ssl;
	private Duration timeout;
	private Duration connectTimeout;
	private String clientName;
	
	private ClientType clientType;
	private Sentinel sentinel;
	private Cluster cluster;
	private final Jedis jedis = new Jedis();
	private final Lettuce lettuce = new Lettuce();
	
	public static class Jedis {
		private Pool pool;
	}
	public static class Lettuce {
		private Duration shutdownTimeout = Duration.ofMillis(100);
		private Pool pool;
	}
	public static class Pool {
		private int maxIdle = 8;
		private int minIdle = 0;
		private int maxActive = 8;
		private Duration maxWait = Duration.ofMillis(-1);
		private Duration timeBetweenEvictionRuns;
	}
}

spring.cache.type=redis
spring.cache.redis.timeToLive=60000
spring.cache.redis.useKeyPrefix=true
spring.cache.redis.keyPrefix=PRE-

# 缓存时间:毫秒
spring.redis.host=xxx
spring.redis.port=6379
spring.redis.password=xx
spring.redis.timeout=5000
spring.redis.pool.max-idle=8
spring.redis.pool.min-idle=0
spring.redis.pool.max-active=8
spring.redis.pool.max-wait=-1

spring-boot-autoconfigure.jar里面的
org.springframework.boot.autoconfigure.cache.CacheType 定义了几种spring缓存类型
GENERICJCACHEEHCACHEREDISSIMPLENONE

Redis示例

Redis示例直接使用原先的示例,不需修改

打印测试信息

spring中Redis缓存配置原理

spring-boot-autoconfigure.jar 中有一个配置类RedisCacheConfiguration
如果应用包含RedisConnectionFactory.classRedisConnectionFactory对象,
并且不能有其他CacheManager对象,
那么配置文件RedisCacheConfiguration会在RedisAutoConfiguration之后生效,然后会实例化一个RedisCacheManager 对象

其中
spring-boot-autoconfigure.jar中的类有:RedisCacheConfiguration RedisAutoConfiguration RedisProperties
LettuceConnectionConfiguration JedisConnectionConfiguration

spring-data-redis.jar中的类有:RedisConnectionFactory RedisOperations

@Configuration
@ConditionalOnClass(RedisConnectionFactory.class)
@AutoConfigureAfter(RedisAutoConfiguration.class)
@ConditionalOnBean(RedisConnectionFactory.class)
@ConditionalOnMissingBean(CacheManager.class)
@Conditional(CacheCondition.class)
class RedisCacheConfiguration {
	@Bean
	RedisCacheManager cacheManager(CacheProperties cacheProperties, CacheManagerCustomizers cacheManagerCustomizers,
			ObjectProvider<org.springframework.data.redis.cache.RedisCacheConfiguration> redisCacheConfiguration,
			ObjectProvider<RedisCacheManagerBuilderCustomizer> redisCacheManagerBuilderCustomizers,
			RedisConnectionFactory redisConnectionFactory, ResourceLoader resourceLoader) {
		RedisCacheManagerBuilder builder = RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(
				determineConfiguration(cacheProperties, redisCacheConfiguration, resourceLoader.getClassLoader()));
		List<String> cacheNames = cacheProperties.getCacheNames();
		if (!cacheNames.isEmpty()) {
			builder.initialCacheNames(new LinkedHashSet<>(cacheNames));
		}
		if (cacheProperties.getRedis().isEnableStatistics()) {
			builder.enableStatistics();
		}
		redisCacheManagerBuilderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
		return cacheManagerCustomizers.customize(builder.build());
	}
}
@Configuration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {
	@Bean
	@ConditionalOnMissingBean(name = "redisTemplate")
	public RedisTemplate<Object, Object> redisTemplate(
			RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
		RedisTemplate<Object, Object> template = new RedisTemplate<>();
		template.setConnectionFactory(redisConnectionFactory);
		return template;
	}
	@Bean
	@ConditionalOnMissingBean
	public StringRedisTemplate stringRedisTemplate(
			RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
		StringRedisTemplate template = new StringRedisTemplate();
		template.setConnectionFactory(redisConnectionFactory);
		return template;
	}
}

Jedis配置类

在classpath下能找到org.apache.commons.pool2.impl.GenericObjectPool.class, JedisConnection.class, redis.clients.jedis.Jedis.class则Jedis配置类生效

redis.clients.jedis.Jedis.classjedis.jar
org.apache.commons.pool2.impl.GenericObjectPool.classcommons-pools.jar

@Configuration
@ConditionalOnClass({ GenericObjectPool.class, JedisConnection.class, Jedis.class })
class JedisConnectionConfiguration extends RedisConnectionConfiguration {
	private final RedisProperties properties;
	@Bean
	@ConditionalOnMissingBean(RedisConnectionFactory.class)
	public JedisConnectionFactory redisConnectionFactory() throws UnknownHostException {
		return createJedisConnectionFactory();
	}
}

Lettuce配置类

在classpath下能找到io.lettuce.core.RedisClient.class, `则Lettuce配置类生效

@Configuration
@ConditionalOnClass(RedisClient.class)
class LettuceConnectionConfiguration extends RedisConnectionConfiguration {
	@Bean
	@ConditionalOnMissingBean(RedisConnectionFactory.class)
	public LettuceConnectionFactory redisConnectionFactory(
			ClientResources clientResources) throws UnknownHostException {
		LettuceClientConfiguration clientConfig = getLettuceClientConfiguration(
				clientResources, this.properties.getLettuce().getPool());
		return createLettuceConnectionFactory(clientConfig);
	}
}

redis配置类

@ConfigurationProperties(prefix = "spring.redis")
public class RedisProperties {
	private int database = 0;
	private String url;
	private String host = "localhost";
	private String password;
	private int port = 6379;
	private boolean ssl;
	private Duration timeout;
	private Sentinel sentinel;
	private Cluster cluster;
	private final Jedis jedis = new Jedis();
	private final Lettuce lettuce = new Lettuce();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qq_26264237

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值