首页
友链
Search
1
JAVA IO
194 阅读
2
SpringBoot整合SpringCache
161 阅读
3
Docker搭建Typecho博客
159 阅读
4
wlop 4K 壁纸 4k8k 动态 壁纸
143 阅读
5
微服务项目搭建
109 阅读
解决方案
JAVA基础
JVM
多线程
开源框架
数据库
前端
分布式
框架整合
中间件
容器部署
设计模式
数据结构与算法
开发工具
百度网盘资源
天翼网盘资源
阿里网盘资源
登录
Search
标签搜索
java
javase
springboot
docker
thread
spring
分布式
锁
redis
linux
typecho
源码
mysql
software
git
算法
synchronized
ArrayList
springboot整合
ThreadPool
少年
累计撰写
130
篇文章
累计收到
5
条评论
首页
栏目
解决方案
JAVA基础
JVM
多线程
开源框架
数据库
前端
分布式
框架整合
中间件
容器部署
设计模式
数据结构与算法
开发工具
百度网盘资源
天翼网盘资源
阿里网盘资源
页面
友链
搜索到
7
篇与
redis
的结果
2022-03-24
SpringBoot整合SpringCache
SpringBoot整合SpringCache1、引入依赖<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency>2、引入redis依赖<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>配置redis地址密码等等,可参考springboo整合redis3、默认配置自动配置// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package org.springframework.boot.autoconfigure.cache; import java.util.List; import java.util.stream.Collectors; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration; import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; import org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.EntityManagerFactoryDependsOnPostProcessor; import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cache.CacheManager; import org.springframework.cache.interceptor.CacheAspectSupport; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.context.annotation.ImportSelector; import org.springframework.core.type.AnnotationMetadata; import org.springframework.orm.jpa.AbstractEntityManagerFactoryBean; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.util.Assert; @Configuration( proxyBeanMethods = false ) @ConditionalOnClass({CacheManager.class}) @ConditionalOnBean({CacheAspectSupport.class}) @ConditionalOnMissingBean( value = {CacheManager.class}, name = {"cacheResolver"} ) @EnableConfigurationProperties({CacheProperties.class}) @AutoConfigureAfter({CouchbaseDataAutoConfiguration.class, HazelcastAutoConfiguration.class, HibernateJpaAutoConfiguration.class, RedisAutoConfiguration.class}) @Import({CacheAutoConfiguration.CacheConfigurationImportSelector.class, CacheAutoConfiguration.CacheManagerEntityManagerFactoryDependsOnPostProcessor.class}) public class CacheAutoConfiguration { public CacheAutoConfiguration() { } @Bean @ConditionalOnMissingBean public CacheManagerCustomizers cacheManagerCustomizers(ObjectProvider<CacheManagerCustomizer<?>> customizers) { return new CacheManagerCustomizers((List)customizers.orderedStream().collect(Collectors.toList())); } @Bean public CacheAutoConfiguration.CacheManagerValidator cacheAutoConfigurationValidator(CacheProperties cacheProperties, ObjectProvider<CacheManager> cacheManager) { return new CacheAutoConfiguration.CacheManagerValidator(cacheProperties, cacheManager); } static class CacheConfigurationImportSelector implements ImportSelector { CacheConfigurationImportSelector() { } public String[] selectImports(AnnotationMetadata importingClassMetadata) { CacheType[] types = CacheType.values(); String[] imports = new String[types.length]; for(int i = 0; i < types.length; ++i) { imports[i] = CacheConfigurations.getConfigurationClass(types[i]); } return imports; } } static class CacheManagerValidator implements InitializingBean { private final CacheProperties cacheProperties; private final ObjectProvider<CacheManager> cacheManager; CacheManagerValidator(CacheProperties cacheProperties, ObjectProvider<CacheManager> cacheManager) { this.cacheProperties = cacheProperties; this.cacheManager = cacheManager; } public void afterPropertiesSet() { Assert.notNull(this.cacheManager.getIfAvailable(), () -> { return "No cache manager could be auto-configured, check your configuration (caching type is '" + this.cacheProperties.getType() + "')"; }); } } @ConditionalOnClass({LocalContainerEntityManagerFactoryBean.class}) @ConditionalOnBean({AbstractEntityManagerFactoryBean.class}) static class CacheManagerEntityManagerFactoryDependsOnPostProcessor extends EntityManagerFactoryDependsOnPostProcessor { CacheManagerEntityManagerFactoryDependsOnPostProcessor() { super(new String[]{"cacheManager"}); } } }所有相关配置都在CacheProperties。重点关注自动配置中的: static class CacheConfigurationImportSelector implements ImportSelector { CacheConfigurationImportSelector() { } public String[] selectImports(AnnotationMetadata importingClassMetadata) { CacheType[] types = CacheType.values(); String[] imports = new String[types.length]; for(int i = 0; i < types.length; ++i) { imports[i] = CacheConfigurations.getConfigurationClass(types[i]); } return imports; } }CacheConfigurations.getConfigurationClass(types[i]); static String getConfigurationClass(CacheType cacheType) { String configurationClassName = (String)MAPPINGS.get(cacheType); Assert.state(configurationClassName != null, () -> { return "Unknown cache type " + cacheType; }); return configurationClassName; }MAPPINGS.get(cacheType);static { Map<CacheType, String> mappings = new EnumMap(CacheType.class); mappings.put(CacheType.GENERIC, GenericCacheConfiguration.class.getName()); mappings.put(CacheType.EHCACHE, EhCacheCacheConfiguration.class.getName()); mappings.put(CacheType.HAZELCAST, HazelcastCacheConfiguration.class.getName()); mappings.put(CacheType.INFINISPAN, InfinispanCacheConfiguration.class.getName()); mappings.put(CacheType.JCACHE, JCacheCacheConfiguration.class.getName()); mappings.put(CacheType.COUCHBASE, CouchbaseCacheConfiguration.class.getName()); mappings.put(CacheType.REDIS, RedisCacheConfiguration.class.getName()); mappings.put(CacheType.CAFFEINE, CaffeineCacheConfiguration.class.getName()); mappings.put(CacheType.SIMPLE, SimpleCacheConfiguration.class.getName()); mappings.put(CacheType.NONE, NoOpCacheConfiguration.class.getName()); MAPPINGS = Collections.unmodifiableMap(mappings); }mappings.put(CacheType.REDIS, RedisCacheConfiguration.class.getName());CacheAutoConfiguration会导入RedisCacheConfiguration;// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package org.springframework.boot.autoconfigure.cache; import java.util.LinkedHashSet; import java.util.List; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.cache.CacheProperties.Redis; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; import org.springframework.cache.CacheManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ResourceLoader; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.cache.RedisCacheManager.RedisCacheManagerBuilder; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializationContext.SerializationPair; @Configuration( proxyBeanMethods = false ) @ConditionalOnClass({RedisConnectionFactory.class}) @AutoConfigureAfter({RedisAutoConfiguration.class}) @ConditionalOnBean({RedisConnectionFactory.class}) @ConditionalOnMissingBean({CacheManager.class}) @Conditional({CacheCondition.class}) class RedisCacheConfiguration { 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(this.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 (RedisCacheManager)cacheManagerCustomizers.customize(builder.build()); } private org.springframework.data.redis.cache.RedisCacheConfiguration determineConfiguration(CacheProperties cacheProperties, ObjectProvider<org.springframework.data.redis.cache.RedisCacheConfiguration> redisCacheConfiguration, ClassLoader classLoader) { return (org.springframework.data.redis.cache.RedisCacheConfiguration)redisCacheConfiguration.getIfAvailable(() -> { return this.createConfiguration(cacheProperties, classLoader); }); } private org.springframework.data.redis.cache.RedisCacheConfiguration createConfiguration(CacheProperties cacheProperties, ClassLoader classLoader) { Redis redisProperties = cacheProperties.getRedis(); org.springframework.data.redis.cache.RedisCacheConfiguration config = org.springframework.data.redis.cache.RedisCacheConfiguration.defaultCacheConfig(); config = config.serializeValuesWith(SerializationPair.fromSerializer(new JdkSerializationRedisSerializer(classLoader))); if (redisProperties.getTimeToLive() != null) { config = config.entryTtl(redisProperties.getTimeToLive()); } if (redisProperties.getKeyPrefix() != null) { config = config.prefixCacheNameWith(redisProperties.getKeyPrefix()); } if (!redisProperties.isCacheNullValues()) { config = config.disableCachingNullValues(); } if (!redisProperties.isUseKeyPrefix()) { config = config.disableKeyPrefix(); } return config; } } 关注里面的方法:@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(this.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 (RedisCacheManager)cacheManagerCustomizers.customize(builder.build()); }相当于自动配置好了缓存管理器RedisCacheManager,cacheProperties.getCacheNames();方法会读取yml里面的配置,接着初始化缓存builder.initialCacheNames(new LinkedHashSet(cacheNames)); public RedisCacheManager.RedisCacheManagerBuilder initialCacheNames(Set<String> cacheNames) { Assert.notNull(cacheNames, "CacheNames must not be null!"); cacheNames.forEach((it) -> { this.withCacheConfiguration(it, this.defaultCacheConfiguration); }); return this; }this.withCacheConfiguration(it, this.defaultCacheConfiguration);public RedisCacheManager.RedisCacheManagerBuilder withCacheConfiguration(String cacheName, RedisCacheConfiguration cacheConfiguration) { Assert.notNull(cacheName, "CacheName must not be null!"); Assert.notNull(cacheConfiguration, "CacheConfiguration must not be null!"); this.initialCaches.put(cacheName, cacheConfiguration); return this; }RedisCacheConfiguration中默认缓存定义规则:private org.springframework.data.redis.cache.RedisCacheConfiguration createConfiguration(CacheProperties cacheProperties, ClassLoader classLoader) { Redis redisProperties = cacheProperties.getRedis(); org.springframework.data.redis.cache.RedisCacheConfiguration config = org.springframework.data.redis.cache.RedisCacheConfiguration.defaultCacheConfig(); config = config.serializeValuesWith(SerializationPair.fromSerializer(new JdkSerializationRedisSerializer(classLoader))); if (redisProperties.getTimeToLive() != null) { config = config.entryTtl(redisProperties.getTimeToLive()); } if (redisProperties.getKeyPrefix() != null) { config = config.prefixCacheNameWith(redisProperties.getKeyPrefix()); } if (!redisProperties.isCacheNullValues()) { config = config.disableCachingNullValues(); } if (!redisProperties.isUseKeyPrefix()) { config = config.disableKeyPrefix(); } return config; }redisProperties也就是从yml中得到的配置。4、配置需要配置的地方:配置使用redis作为缓存spring.cache.type=redis使用缓存,官方文档 https://docs.spring.io/spring-framework/docs/5.3.18-SNAPSHOT/reference/html/integration.html#cache重点关注几个注解:@Cacheable: Triggers cache population. @CacheEvict: Triggers cache eviction. @CachePut: Updates the cache without interfering with the method execution. @Caching: Regroups multiple cache operations to be applied on a method. @CacheConfig: Shares some common cache-related settings at class-level.@Cacheable: Triggers cache population.触发将数据保存到缓存的操作@CacheEvict: Triggers cache eviction.触发将数据从缓存删除的操作@CachePut: Updates the cache without interfering with the method execution.不影响方法执行更新缓存@Caching: Regroups multiple cache operations to be applied on a method.组合以上多个操作@CacheConfig: Shares some common cache-related settings at class-level.在类级别共享缓存的相同配置5、自定义规则第一步、启动类上开启缓存功能:@EnableCaching第二部、只需要注解就能完成缓存操作@Cacheable:1、代表当前方法的结果需要缓存,如果缓存中有,方法不用调用。如果缓存中没有,会调用方法,最后将方法的结果放入缓存。2、每一个需要缓存的数据我们都来指定要翻到那个名字的缓存【缓存的分区,推荐按照业务类型分】。3、key默认自动生成,value默认是使用jdk默认序列化机制。默认时间是-1,永不过期。因此需要我们自定义规则:自定义规则/** * @description: Cache redis数据格式配置 * @date: 2022/2/17 21:59 * @version: 1.0 */ import com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer; import org.springframework.boot.autoconfigure.cache.CacheProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCacheConfiguration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializationContext; import org.springframework.data.redis.serializer.StringRedisSerializer; @EnableConfigurationProperties(CacheProperties.class) @Configuration @EnableCaching public class MyCacheConfig { @Bean RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties){ RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig(); config = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())); config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericFastJsonRedisSerializer())); CacheProperties.Redis redisProperties = cacheProperties.getRedis(); if (redisProperties.getTimeToLive() != null) { config = config.entryTtl(redisProperties.getTimeToLive()); } // if (redisProperties.getKeyPrefix() != null) { // config = config.prefixCacheNameWith(redisProperties.getKeyPrefix()); // } if (!redisProperties.isCacheNullValues()) { config = config.disableCachingNullValues(); } if (!redisProperties.isUseKeyPrefix()) { config = config.disableKeyPrefix(); } return config; } }6、使用示例// 使用缓存注解方式,key:为方法名 @Override @Cacheable(value = {"record"},key = "#root.method.name") public RecordEntity getRecordAllInfoById(Long id) { //未使用注解缓存方案 // RecordEntity recordEntity = null; // // ValueOperations<String, String> forValue = redisTemplate.opsForValue(); // String recordData = forValue.get("RecordData"); // if(recordData==null){ // System.out.println("缓存没数据,执行查询数据库方法。。。。"); // recordEntity = getEntityByIdByFbsRedisson(id); // }else{ // System.out.println("从缓存中获取数据。。。。。"); // recordEntity = JSON.parseObject(recordData, new TypeReference<RecordEntity>() { // }); // } //使用注解缓存后 RecordEntity recordEntity = getEntityById(id); if(recordEntity!=null){ Long categoryId = recordEntity.getCategoryId(); Long[] catelogPath = findCatelogPath(categoryId); recordEntity.setCatelogPath(catelogPath); } return recordEntity; }key使用SPEL表达式规则可参考官网中 Using Custom Annotations使用规则。https://docs.spring.io/spring-framework/docs/5.3.18-SNAPSHOT/reference/html/integration.html#cache-annotation-stereotype
2022年03月24日
161 阅读
0 评论
7 点赞
2022-03-08
分布锁解决方案
分布锁有哪些解决方案?1.Reids的分布式锁,很多大公司会基于Reidis做扩展开发。setnxkey value,Redisson。基于Zookeeper。顺序临时节点。基于数据库,比如Mysql。主键或唯一索引的唯一性。
2022年03月08日
21 阅读
0 评论
3 点赞
2022-03-08
Redis分布式锁命令
SETNX格式:setnx key value将key的值设为value,当且仅当key不存在。若给定的key已经存在,则SETNX不做任何动作。SETNX是SET if Not eXists](如果不存在,则SET)的简写。
2022年03月08日
44 阅读
0 评论
2 点赞
2022-03-08
Redis做分布式锁死锁问题及解决方案
情况1:加锁,没有释放锁。需要加释放锁的操作。比如delete keyI,根据get获取value删除。情况2:加锁后,程序还没有执行释放锁,程序挂了。需要用的key的过期机制。情况3: 保证情况2的原子性。
2022年03月08日
21 阅读
0 评论
2 点赞
2022-03-08
Redis实现分布式锁
Redis如何做分布式锁?假设有两个服务A、B都希望获得锁,执行过程大致如下:Step1:服务A为了获得锁,向Redis发起如下命令:SET productld:lock 0xx9p03001 NXEX30000其中,"productld"由自己定义,可以是与本次业务有关的id,“0xx9p03001"是一串随机值,必须保证全局唯一,“NX"指的是当且仅当key(也就是案例中的“productld;lock'")在Redis中不存在时,返回执行成功,否则执行失败。”EX30000"指的是在30秒后,key将被自动删除。执行命令后返回成功,表明服务成功的获得了锁。Step2:服务B为了获得锁,向Redis发起同样的命令:SET productld:lock 0000111 NXEX30000由于Redis内已经存在同名key,且并未过期,因此命令执行失败,服务B未能获得锁。服务B进入循环请求状态,比如每隔1秒钟(自行设置)向Redis发送请求,直到执行成功并获得锁。Step3:服务A的业务代码执行时长超过了30秒,导致key超时,因此Redis自动删除了key。此时服务B再次发送命令执行成功,假设本次请求中设置的value值为0000222。此时需要在服务A中对key进行续期。Step4:服务A执行完毕,为了释放锁,服务A会主动向Redis发起删除key的请求。注意:在删除key之前,一定要判断服务A持有的value与Redis内存储的value是否一致。比如当前场景下,Redis中的锁早就不是服务A持有的那一把了,而是由服务2创建,如果贸然使用服务A持有的key来删除锁,则会误将服务2的锁释放掉。此外,由于删除锁时涉及到一系列判断逻辑,因此一般使用lua脚本。
2022年03月08日
39 阅读
0 评论
3 点赞
1
2