Spring Boot 集成 Cache缓存

一、Spring Boot 集成 Cache缓存

配置文件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

二、Cache缓存在Spring Boot中的测试代码

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());
		}


	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值