赞
踩
配置文件pom.xml:
<!-- cache springboot缓存-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
配置文件application.properties:
##cache springboot缓存配置
#simple:使用springboot自带的缓存;适合单体应用或者开发环境使用
#none:关闭缓存
#redis:使用redis作为缓存
spring.cache.type=redis
#基于redis缓存的缓存过期时间为1分钟
spring.cache.redis.time-to-live=60000
CacheController文件代码如下:
package com.example.shopgoods.controller.cache; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; /** * @Author: zp * @Date: 2019/6/19 14:48 * @Description: */ @RestController @RequestMapping("/cache") public class CacheController { @Autowired private CacheService cacheService; @PostMapping("/test_1") public String cacheTest1(@RequestParam(value = "id") int id){ String str = cacheService.getCache(id); return str; } @PostMapping("/test_2") public String cacheTest2(@RequestParam(value = "id") int id){ String str = cacheService.getCacheName(id); return str; } }
CacheService文件代码如下:
package com.example.shopgoods.controller.cache;
/**
* @Author: zp
* @Date: 2019/6/19 14:50
* @Description:
*/
public interface CacheService {
String getCache(int id);
String getCacheName(int id);
}
CacheServiceImpl文件代码如下:
package com.example.shopgoods.controller.cache.Impl; import com.example.shopgoods.controller.cache.CacheService; import org.springframework.cache.annotation.CacheConfig; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; /** * @Author: zp * @Date: 2019/6/19 14:50 * @Description: */ @Service //该注解作用于类上,为此类里的方法的缓存注解提供默认值 @CacheConfig(cacheNames = "cache") public class CacheServiceImpl implements CacheService { @Override //id小于5的都需要缓存 @Cacheable(cacheNames = "getCache", condition = "#id < 5") public String getCache(int id) { String str = ""; if (id == 1) { str = "C_1 ---->" + id; } else if (id == 2) { str = "C_2 ---->" + id; } else { str = "cache ---->" + id; } return str; } @Override @Cacheable() public String getCacheName(int id) { return String.valueOf(id); } }
CacheConfig文件代码如下:(此配置介绍了实现Redis两级缓存的原理)
package com.example.shopgoods.controller.cache.config; import java.io.UnsupportedEncodingException; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.Cache; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCache; import org.springframework.data.redis.cache.RedisCacheConfiguration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.cache.RedisCacheWriter; import org.springframework.data.redis.connection.Message; import org.springframework.data.redis.connection.MessageListener; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.listener.PatternTopic; import org.springframework.data.redis.listener.RedisMessageListenerContainer; import org.springframework.data.redis.listener.adapter.MessageListenerAdapter; import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializationContext.SerializationPair; /** * 支持一二级缓存,使得性能到达极致, * @author xiandafu * */ //@Configuration public class CacheConfig { // 定义一个redis 的频道,默认叫cache,用于pub/sub @Value("${springext.cache.redis.topic:cache}") String topicName; @Bean public TwoLevelCacheManager cacheManager(StringRedisTemplate redisTemplate) { //RedisCache需要一个RedisCacheWriter来实现读写Redis RedisCacheWriter writer = RedisCacheWriter.lockingRedisCacheWriter(redisTemplate.getConnectionFactory()); /*SerializationPair用于Java和Redis之间的序列化和反序列化*/ SerializationPair pair = SerializationPair.fromSerializer(new JdkSerializationRedisSerializer(this.getClass().getClassLoader())); /*构造一个RedisCache的配置。*/ RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(pair); /*创建CacheManager,并返回给Spring容器*/ TwoLevelCacheManager cacheManager = new TwoLevelCacheManager(redisTemplate,writer,config); return cacheManager; } // Redis message,参考Redis一章 @Bean RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory, MessageListenerAdapter listenerAdapter) { RedisMessageListenerContainer container = new RedisMessageListenerContainer(); container.setConnectionFactory(connectionFactory); container.addMessageListener(listenerAdapter, new PatternTopic(topicName)); return container; } @Bean MessageListenerAdapter listenerAdapter(final TwoLevelCacheManager cacheManager) { return new MessageListenerAdapter(new MessageListener() { public void onMessage(Message message, byte[] pattern) { byte[] bs = message.getChannel(); try { // Sub 一个消息,通知缓存管理器 String type = new String(bs, "UTF-8"); String cacheName = new String(message.getBody(),"UTF-8"); cacheManager.receiver(cacheName); } catch (UnsupportedEncodingException e) { e.printStackTrace(); // 不可能出错,忽略 } } }); } class TwoLevelCacheManager extends RedisCacheManager { RedisTemplate redisTemplate; public TwoLevelCacheManager(RedisTemplate redisTemplate,RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) { super(cacheWriter,defaultCacheConfiguration); this.redisTemplate = redisTemplate; } //使用RedisAndLocalCache代替Spring Boot自带的RedisCache @Override protected Cache decorateCache(Cache cache) { return new RedisAndLocalCache(this, (RedisCache) cache); } //通过其他分布式节点,缓存改变 public void publishMessage(String cacheName) { this.redisTemplate.convertAndSend(topicName, cacheName); } // 接受一个消息清空本地缓存 public void receiver(String name) { RedisAndLocalCache cache = ((RedisAndLocalCache) this.getCache(name)); if(cache!=null){ cache.clearLocal(); } } } class RedisAndLocalCache implements Cache { // 本地缓存提供 ConcurrentHashMap<Object, Object> local = new ConcurrentHashMap<Object, Object>(); RedisCache redisCache; TwoLevelCacheManager cacheManager; public RedisAndLocalCache(TwoLevelCacheManager cacheManager, RedisCache redisCache) { this.redisCache = redisCache; this.cacheManager = cacheManager; } @Override public String getName() { return redisCache.getName(); } @Override public Object getNativeCache() { return redisCache.getNativeCache(); } @Override public ValueWrapper get(Object key) { //一级缓存先取 ValueWrapper wrapper = (ValueWrapper) local.get(key); if (wrapper != null) { return wrapper; } else { // 二级缓存取 wrapper = redisCache.get(key); if (wrapper != null) { local.put(key, wrapper); } return wrapper; } } @Override public <T> T get(Object key, Class<T> type) { return redisCache.get(key, type); } @Override public <T> T get(Object key, Callable<T> valueLoader) { return redisCache.get(key, valueLoader); } @Override public void put(Object key, Object value) { System.out.println(value.getClass().getClassLoader()); redisCache.put(key, value); //通知其他节点缓存更更新 clearOtherJVM(); } @Override public ValueWrapper putIfAbsent(Object key, Object value) { ValueWrapper v = redisCache.putIfAbsent(key, value); clearOtherJVM(); return v; } @Override public void evict(Object key) { redisCache.evict(key); //通知其他节点缓存更更新 clearOtherJVM(); } @Override public void clear() { redisCache.clear(); } /** * 提供给CacheManager清空一级缓存 */ public void clearLocal() { this.local.clear(); } /** * 通知其他节点缓存更更新 */ protected void clearOtherJVM() { cacheManager.publishMessage(redisCache.getName()); } } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。