博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SpringBoot资料整理(5)
阅读量:6808 次
发布时间:2019-06-26

本文共 5938 字,大约阅读时间需要 19 分钟。

hot3.png

缓存系统的用来代替直接访问数据库,用来提升系统性能,减小数据库复杂。早期缓存跟系统在一个虚拟机里,这样内存访问,速度最快。 后来应用系统水平扩展,缓存作为一个独立系统存在,如redis,但是每次从缓存获取数据,都还是要通过网络访问才能获取,效率相对于早先从内存里获取,还是差了点。如果一个应用,比如传统的企业应用,一次页面显示,要访问数次redis,那效果就不是特别好,因此,现在有人提出了一二级缓存。即一级缓存跟系统在一个虚拟机内,这样速度最快。二级缓存位于redis里,当一级缓存没有数据的时候,再从redis里获取,并同步到一级缓存里。

现在实现这种一二级缓存的也挺多的,比如 hazelcast,新版的Ehcache..不过,实际上,如果你用spring boot,手里又一个Redis,则不需要搞hazelcastEhcache,只需要200行代码,就能在spring boot基础上,提供一个一二级缓存,代码如下:

import java.io.UnsupportedEncodingException;import java.util.concurrent.ConcurrentHashMap;import org.springframework.beans.factory.annotation.Value;import org.springframework.boot.autoconfigure.AutoConfigureBefore;import org.springframework.boot.bind.RelaxedPropertyResolver;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Condition;import org.springframework.context.annotation.ConditionContext;import org.springframework.context.annotation.Conditional;import org.springframework.context.annotation.Configuration;import org.springframework.core.type.AnnotatedTypeMetadata;import org.springframework.data.redis.cache.RedisCache;import org.springframework.data.redis.cache.RedisCacheManager;import org.springframework.data.redis.cache.RedisCachePrefix;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.RedisOperations;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.listener.PatternTopic;import org.springframework.data.redis.listener.RedisMessageListenerContainer;import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;@Configuration@Conditional(StarterCacheCondition.class)public class CacheConfig {		@Value("${springext.cache.redis.topic:cache}")	String topicName ;				@Bean	public MyRedisCacheManager cacheManager(RedisTemplate
redisTemplate) { MyRedisCacheManager cacheManager = new MyRedisCacheManager(redisTemplate); cacheManager.setUsePrefix(true); return cacheManager; }@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(MyRedisCacheManager cacheManager ) { return new MessageListenerAdapter(new MessageListener(){ @Override public void onMessage(Message message, byte[] pattern) { byte[] bs = message.getChannel(); try { String type = new String(bs,"UTF-8"); cacheManager.receiver(type); } catch (UnsupportedEncodingException e) { e.printStackTrace(); // 不可能出错 } } }); } class MyRedisCacheManager extends RedisCacheManager{ public MyRedisCacheManager(RedisOperations redisOperations) { super(redisOperations); } @SuppressWarnings("unchecked") @Override protected RedisCache createCache(String cacheName) { long expiration = computeExpiration(cacheName); return new MyRedisCache(this,cacheName, (this.isUsePrefix()? this.getCachePrefix().prefix(cacheName) : null), this.getRedisOperations(), expiration); } /** * get a messsage for update cache * @param cacheName */ public void receiver(String cacheName){ MyRedisCache cache = (MyRedisCache)this.getCache(cacheName); if(cache==null){ return ; } cache.cacheUpdate(); } //notify other redis clent to update cache( clear local cache in fact) public void publishMessage(String cacheName){ this.getRedisOperations().convertAndSend(topicName, cacheName); } } class MyRedisCache extends RedisCache{ //local cache for performace ConcurrentHashMap
local = new ConcurrentHashMap<>(); MyRedisCacheManager cacheManager; public MyRedisCache(MyRedisCacheManager cacheManager,String name, byte[] prefix, RedisOperations
redisOperations, long expiration) { super(name, prefix, redisOperations, expiration); this.cacheManager = cacheManager; } @Override public ValueWrapper get(Object key) { ValueWrapper wrapper = local.get(key); if(wrapper!=null){ return wrapper; }else{ wrapper = super.get(key); if(wrapper!=null){ local.put(key, wrapper); } return wrapper; } } @Override public void put(final Object key, final Object value) { super.put(key, value); cacheManager.publishMessage(super.getName()); } @Override public void evict(Object key) { super.evict(key); cacheManager.publishMessage(super.getName()); } @Override public ValueWrapper putIfAbsent(Object key, final Object value){ ValueWrapper wrapper = super.putIfAbsent(key, value); cacheManager.publishMessage(super.getName()); return wrapper; } public void cacheUpdate(){ //clear all cache for simplification local.clear(); } } }class StarterCacheCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { RelaxedPropertyResolver resolver = new RelaxedPropertyResolver( context.getEnvironment(), "springext.cache."); String env = resolver.getProperty("type"); if(env==null){ return false; } return "local2redis".equalsIgnoreCase(env.toLowerCase()); }}

代码的核心在于spring boot提供一个概念CacheManager&Cache用来表示缓存,并提供了多达8种实现,但由于缺少一二级缓存,因此,需要在Redis基础上扩展,因此实现了MyRedisCacheManger,以及MyRedisCache,增加一个本地缓存。

一二级缓存需要解决的的一个问题是缓存更新的时候,必须通知其他节点的springboot应用缓存更新。这里可以用Redis的 Pub/Sub 功能来实现,具体可以参考listenerAdapter方法实现。

使用的时候,需要配置如下,这样,就可以使用缓存了,性能杠杠的好

 

springext.cache.type=local2redis# Redis服务器连接端口spring.redis.host=172.16.86.56spring.redis.port=6379

 

转载于:https://my.oschina.net/undefine/blog/848487

你可能感兴趣的文章
CSS框架学习资料汇总
查看>>
我的友情链接
查看>>
linux硬链接和软链接的区别
查看>>
Java记录 -59- SortedSet
查看>>
VMware克隆CentOS6.4后 eth0无法初始化
查看>>
如何在RedHat 5.4上使用免费的YUM源
查看>>
.NET MVC4 本地正常 部署 服务器错误
查看>>
JMX Java Management Extensions
查看>>
[置顶] javascript中的数组对象以及json学习笔记
查看>>
Android第九天
查看>>
浅学JSON——Json.NET之首次试手
查看>>
[转]Hyper-V功能大跃进 或引发市场洗牌
查看>>
我的友情链接
查看>>
git 遇到fatal:multiple stage entries for merged file
查看>>
文件系统管理 之 Fedora Core 4.0 HAL配置即插即用移动存储(USB及1394)的实践
查看>>
Android Day01-Android与Java的区别总结
查看>>
redis指令
查看>>
We7CMS内容管理系统助阵政府完善信息公开制度
查看>>
Magento版本比较:Magento社区版 vs Magento企业版本 vs MEC Magento专业版2
查看>>
kafka入门:简介、使用场景、设计原理
查看>>