springboot定制redis缓存

  1. key生成核心逻辑
    package com.kiiik.config.redis.cache;
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    
    import org.apache.commons.lang.ArrayUtils;
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.springframework.cache.annotation.CacheEvict;
    import org.springframework.cache.annotation.CachePut;
    import org.springframework.cache.annotation.Cacheable;
    import org.springframework.util.CollectionUtils;
    /**
     *作者 : iechenyb<br>
     *类描述: 说点啥<br>
     *创建时间: 2018年11月20日
     * "userInfor#1800#90";
     */
    public class BaseCacheKey {
    	public final static String CACHE_SPLIT = "#";
    	Log log = LogFactory.getLog(BaseCacheKey.class);
    	private final Object[] params;
    	private final int hashCode;
    	private final String className;
    	private final String methodName;
    	private final String simpleName;
    	private  String baseKey=null;//kiiik.zuul.baseKey.***
     
    	public BaseCacheKey(Object target, Method method, Object[] elements) throws Exception{
    		this.className=target.getClass().getName();
    		this.simpleName=target.getClass().getSimpleName();
    		this.methodName=getMethodName(method);
    		this.params = new Object[elements.length];
    		System.arraycopy(elements, 0, this.params, 0, elements.length);
    		this.hashCode=generatorHashCode();
    		initKey(method);
    	}
    	
    	public BaseCacheKey(Object target, Method method) throws Exception{
    		this.className=target.getClass().getName();
    		this.simpleName=target.getClass().getSimpleName();
    		this.methodName=getMethodName(method);
    	    this.params = null;
    	    StringBuilder sb = new StringBuilder();
            sb.append(target.getClass().getName());
            sb.append(method.getName());
         	this.hashCode= sb.toString().hashCode();
         	initKey(method);
    	}
    	//key#timeout#refresh
    	public String initKey(Method method) throws Exception{
    		List<String> keys = new ArrayList<>();
    		if(method.isAnnotationPresent(Cacheable.class)){
    			Cacheable a = method.getAnnotation(Cacheable.class);
    			if(!ArrayUtils.isEmpty(a.cacheNames())){
    				keys = Arrays.asList(a.cacheNames());
    			}else{
    				keys = Arrays.asList(a.value());
    			}
    		}else if(method.isAnnotationPresent(CachePut.class)){
    			CachePut a = method.getAnnotation(CachePut.class);
    			if(!ArrayUtils.isEmpty(a.cacheNames())){
    				keys = Arrays.asList(a.cacheNames());
    			}else{
    				keys = Arrays.asList(a.value());
    			}
    		}else if(method.isAnnotationPresent(CacheEvict.class)){
    			CacheEvict a = method.getAnnotation(CacheEvict.class);
    			if(!ArrayUtils.isEmpty(a.cacheNames())){
    				keys = Arrays.asList(a.cacheNames());
    			}else{
    				keys = Arrays.asList(a.value());
    			}
    		}else{
    			throw new Exception("缓存key的value或者names格式不正确。格式=唯一名称#过期时间#刷新时间");
    		}
    		if(!CollectionUtils.isEmpty(keys)){
    			baseKey = keys.get(0).split(CACHE_SPLIT)[0];
    		}else{
    			baseKey=null;
    		}
    		return baseKey;
    	}
    	
    	private String getMethodName(Method method){
    		StringBuilder builder = new StringBuilder(method.getName());
    		Class<?>[] types = method.getParameterTypes();
    		if(types.length!=0){
    			builder.append("(");
    			for(Class<?> type:types){
    				String name = type.getName();
    				builder.append(name+",");
    			}
    			builder.append(")");
    		}
    		return builder.toString();
    	}
     
    	@Override
    	public boolean equals(Object obj){
    		if(this==obj)
    			return true;
    		if (obj == null)
    			return false;
    		if (getClass() != obj.getClass())
    			return false;
    		BaseCacheKey o=(BaseCacheKey) obj;
    		if(this.hashCode!=o.hashCode())
    			return false;
    		
    		if (!Arrays.equals(params, o.params))
    			return false;
    		
    		return true;
    	}
    	
    	@Override
    	public final int hashCode() {
    		return hashCode;
    	}
    	/**
    	 * 
    	 *作者 : iechenyb<br>
    	 *方法描述: 参数为空时,每个对象都一样<br>
    	 *创建时间: 2018年11月22日
    	 *@return
    	 */
    	private int generatorHashCode() {
    		final int prime = 31;
    		int result = 1;
    		result = prime * result + hashCode;
    		result = prime * result + ((className == null) ? 0 : className.hashCode());
    		result = prime * result + ((methodName == null) ? 0 : methodName.hashCode());
    		if(params.length>0){
    			result = prime * result + Arrays.deepHashCode(params);//没有考虑对象的情况,需要对每个对象参数进行重写hashcode方法
    		}
    		return result;
    	}
        /**
         * 类名+方法名+name|value+hashcode
         */
    	@Override
    	public String toString() {
    		/*return "BaseCacheKey [params=" + Arrays.deepToString(params) + ", className=" + className + ", methodName="
    				+ methodName + "]";*/
    	    return RedisUtils.keyBuilder(simpleName, baseKey, String.valueOf(hashCode));
    	}
    }
    

     

  2. 定制redis缓存
    package com.kiiik.config.redis.cache;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.springframework.data.redis.cache.RedisCache;
    import org.springframework.data.redis.cache.RedisCacheManager;
    import org.springframework.data.redis.core.RedisOperations;
    import org.springframework.util.Assert;
    
    /**
     * 作者 : iechenyb<br>
     * 类描述: 说点啥<br>
     * 创建时间: 2018年11月21日
     */
    public class CustomizeRedisCacheManager extends RedisCacheManager {
    	Log log = LogFactory.getLog(CustomizeRedisCacheManager.class);
    
    	CustomizeRedisCacheManager(RedisOperations<?, ?> redisOperations) {
    		super(redisOperations);
    	}
    
    	@SuppressWarnings("unchecked")
    	@Override
    	protected RedisCache createCache(String cacheName) {
    		Assert.hasText(cacheName, "CacheName must not be null or empty!");
    
    		String[] values = cacheName.split("#");
    
    		long expiration = computeExpiration(values);
    		return new RedisCache(values[0], (isUsePrefix() ? getCachePrefix().prefix(cacheName) : null),
    				getRedisOperations(), expiration, false);
    	}
    
    	private long computeExpiration(String[] values) {
    		if (values.length > 1) {
    			return Long.parseLong(values[1]);
    		}
    		// 如果说想使用默认的过期时间而不指定特殊时间,则可以直接@Cacheable(cacheNames="name"),不需要加'#过期时间'了
    		return super.computeExpiration(values[0]);
    	}
    }
    

     

  3. 定制key生成器
    package com.kiiik.config.redis.cache;
    
    import java.lang.reflect.Method;
    import java.util.HashMap;
    import java.util.Map;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.springframework.cache.CacheManager;
    import org.springframework.cache.annotation.EnableCaching;
    import org.springframework.cache.interceptor.KeyGenerator;
    import org.springframework.context.annotation.Bean;
    import org.springframework.data.redis.connection.RedisConnectionFactory;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
    import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
    import org.springframework.data.redis.serializer.RedisSerializer;
    import org.springframework.data.redis.serializer.StringRedisSerializer;
    import org.springframework.stereotype.Component;
    
    /**
     * 作者 : iechenyb<br>
     * 类描述: 说点啥<br>
     * 创建时间: 2018年11月20日
     */
    @Component("cacheKeyGenerator")
    // 开启缓存
    @EnableCaching
    public class BaseCacheKeyGenerator implements KeyGenerator {
    	Log log = LogFactory.getLog(BaseCacheKeyGenerator.class);
    
    	// private Duration timeToLive = Duration.ZERO;
    	@Override
    	public Object generate(Object target, Method method, Object... params) {
    		try {
    			return new BaseCacheKey(target, method, params).toString();
    		} catch (Exception e) {
    			e.printStackTrace();
    			return null;
    		}
    	}
    
    	/*
    	 * 默认的处理方式
    	 * 
    	 * @Bean public CacheManager cacheManager(RedisTemplate<?,?> redisTemplate)
    	 * {
    	 * 
    	 * redisTemplate.setKeySerializer(keySerializer());
    	 * redisTemplate.setValueSerializer(valueSerializer());
    	 * redisTemplate.setHashKeySerializer(keySerializer());
    	 * redisTemplate.setHashValueSerializer(valueSerializer());
    	 * 
    	 * RedisCacheManager redisCacheManager= new
    	 * RedisCacheManager(redisTemplate);
    	 * redisCacheManager.setDefaultExpiration(3600); Map<String,Long>
    	 * expiresMap=new HashMap<>(); expiresMap.put("Product",5L);
    	 * redisCacheManager.setExpires(expiresMap); return redisCacheManager; }
    	 */
    	// 定制的处理方式
    	@Bean
    	public CacheManager cacheManager(RedisTemplate<?, ?> redisTemplate) {
    		redisTemplate.setKeySerializer(stringKeySerializer());
    		redisTemplate.setValueSerializer(valueSerializer());
    		redisTemplate.setHashKeySerializer(stringKeySerializer());
    		redisTemplate.setHashValueSerializer(valueSerializer());
    
    		CustomizeRedisCacheManager redisCacheManager = new CustomizeRedisCacheManager(redisTemplate);
    		redisCacheManager.setDefaultExpiration(3600);
    		Map<String, Long> expiresMap = new HashMap<>();
    		expiresMap.put("Product", 5L);
    		redisCacheManager.setExpires(expiresMap);
    		return redisCacheManager;
    	}
    
    	@Bean(name = "redisTemplate")
    	public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
    		RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
    		redisTemplate.setConnectionFactory(redisConnectionFactory);
    
    		redisTemplate.setKeySerializer(stringKeySerializer());
    		redisTemplate.setHashKeySerializer(stringKeySerializer());
    		redisTemplate.setValueSerializer(valueSerializer());
    		redisTemplate.setHashValueSerializer(valueSerializer());
    
    		log.debug("自定义RedisTemplate加载完成");
    		return redisTemplate;
    	}
    
    	
    	public JdkSerializationRedisSerializer jdkKeySerializer() {
    		return new JdkSerializationRedisSerializer();
    	}
    	
    	public StringRedisSerializer stringKeySerializer() {
    		return new StringRedisSerializer();
    	}
    
    	private RedisSerializer<Object> valueSerializer() {
    		return new GenericJackson2JsonRedisSerializer();
    	}
    }
    

     

  4. 辅助工具类
    package com.kiiik.config.redis.cache;
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.springframework.util.StringUtils;
    
    import com.cyb.freemarker.mvc.base.BaseController;
    /**
     *作者 : iechenyb<br>
     *类描述: 说点啥<br>
     *创建时间: 2018年11月22日
     */
    
    public class RedisUtils {
    	Log log = LogFactory.getLog(RedisUtils.class);
    
    	 /**
         * 主数据系统标识 
         */
        public static final String KEY_PREFIX = "system:example";
        /**
         * 分割字符,默认[:],使用:可用于rdm分组查看
         */
        private static final String KEY_SPLIT_CHAR = ":";
    
        /**
         * redis的key键规则定义
         * @param module 模块名称
         * @param func 方法名称
         * @param args 参数..
         * @return key
         */
        public static String keyBuilder(String module, String func, String... args) {
            return keyBuilder(null, module, func, args);
        }
        
        private static String keyName(String value) throws Exception{
        	if(StringUtils.isEmpty(value)){
        		throw new Exception("缓存没有定义对应的key名称");
        	}
        	if(value.split("#").length > 0){
        		return value.split("#")[0];
        	}
    		return value;
        }
        public static String keyBuilder(Class<?> clazz, String name) throws Exception {
            return new StringBuffer(KEY_PREFIX)
            		.append(KEY_SPLIT_CHAR)
            		.append(clazz.getSimpleName())
            		.append(KEY_SPLIT_CHAR)
            		.append(keyName(name))
            		.toString();
        }
    
        /**
         * redis的key键规则定义
         * @param module 模块名称
         * @param func 方法名称
         * @param objStr 对象.toString()
         * @return key
         */
        public static String keyBuilder(String module, String func, String objStr) {
            return keyBuilder(null, module, func, new String[]{objStr});
        }
    
        /**
         * redis的key键规则定义
         * @param prefix 项目前缀
         * @param module 模块名称
         * @param func 方法名称
         * @param objStr 对象.toString()
         * @return key
         */
        public static String keyBuilder(String prefix, String module, String func, String objStr) {
            return keyBuilder(prefix, module, func, new String[]{objStr});
        }
    
        /**
         * redis的key键规则定义
         * @param prefix 项目前缀
         * @param module 模块名称
         * @param func 方法名称
         * @param args 参数..
         * @return key
         */
        public static String keyBuilder(String prefix, String module, String func, String... args) {
            // 项目前缀
            if (prefix == null) {
                prefix = KEY_PREFIX;
            }
            StringBuilder key = new StringBuilder(prefix);
            // KEY_SPLIT_CHAR 为分割字符
            key.append(KEY_SPLIT_CHAR).append(module).append(KEY_SPLIT_CHAR).append(func);
            for (String arg : args) {
                key.append(KEY_SPLIT_CHAR).append(arg);
            }
            return key.toString();
        }
    
        /**
         * redis的key键规则定义
         * @param redisEnum 枚举对象
         * @param objStr 对象.toString()
         * @return key
         */
        public static String keyBuilder(RedisEnum redisEnum, String objStr) {
            return keyBuilder(redisEnum.getKeyPrefix(), redisEnum.getModule(), redisEnum.getFunc(), objStr);
        }
        
        public static void main(String[] args) throws Exception {
    		System.out.println(keyBuilder("com.cyb.test", "method", String.valueOf(111)));
    		System.out.println(keyBuilder("com.cyb.test", "method:value", String.valueOf(111)));
    	    System.out.println(keyBuilder(BaseController.class, "aaa"));
        }
    
    }
    
    
    package com.kiiik.config.redis.cache;
    
    /**
     *作者 : iechenyb<br>
     *类描述: 说点啥<br>
     *创建时间: 2018年11月22日
     */
    public enum RedisEnum {
    	/**
         * 数据字典Service - 根据字典类型查询字典数据
         */
    	RedisEnum(
                RedisUtils.KEY_PREFIX, "", "", "");
    
        /**
         * 系统标识
         */
        private String keyPrefix;
        /**
         * 模块名称
         */
        private String module;
        /**
         * 方法名称
         */
        private String func;
        /**
         * 描述
         */
        private String remark;
    
        RedisEnum(String keyPrefix, String module, String func, String remark) {
            this.keyPrefix = keyPrefix;
            this.module = module;
            this.func = func;
            this.remark = remark;
        }
    
    	public String getKeyPrefix() {
    		return keyPrefix;
    	}
    
    	public void setKeyPrefix(String keyPrefix) {
    		this.keyPrefix = keyPrefix;
    	}
    
    	public String getModule() {
    		return module;
    	}
    
    	public void setModule(String module) {
    		this.module = module;
    	}
    
    	public String getFunc() {
    		return func;
    	}
    
    	public void setFunc(String func) {
    		this.func = func;
    	}
    
    	public String getRemark() {
    		return remark;
    	}
    
    	public void setRemark(String remark) {
    		this.remark = remark;
    	}
        
    }
    

     

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
概要介绍: 本课程主要是介绍并实战一款java中间件~redisson,介绍redisson相关的核心技术栈及其典型的应用场景,其中的应用场景就包括布隆过滤器、限流器、短信发送、实时/定时邮件发送、数据字典、分布式服务调度等等,在业界号称是在java项目里正确使用redis的姿势。本课程的目标就在于带领各位小伙伴一起学习、攻克redisson,更好地巩固自己的核心竞争力,而至于跳槽涨薪,自然不在话下!  课程内容: 说起redisson,可能大伙儿不是很熟悉,但如果说起redis,想必肯定很多人都晓得。没错,这家伙字如其名,它就是架设在redis基础上的一款综合性的、新型的中间件,号称是java企业级应用开发中正确使用redis的姿势/客户端实例。 它是架设在redis基础之上,但拥有的功能却远远多于原生Redis 所提供的,比如分布式对象、分布式集合体系、分布式锁以及分布式服务调度等一系列具有分布式特性的对象实例… 而这些东西debug将在本门课程进行淋漓尽致的介绍并实战,除此之外,我们将基于spring boot2.0搭建的多模块项目实战典型的应用场景:对象存储、数据字典、短信发送、实时/定时邮件发送、布隆过滤器、限流组件、分布式服务调度....课程大纲如下所示: 下面罗列一下比较典型的核心技术栈及其实际业务场景的实战,如下图所示为redisson基于订阅-发布模式的核心技术~主题Topic的实际业务场景,即实时发送邮件: 而下图则是基于“多值映射MultiMap”数据结构实战实现的关于“数据字典”的缓存管理: 除此之外,我们还讲解了可以与分布式服务调度中间件dubbo相媲美的功能:分布式远程服务调度,在课程中我们动手搭建了两个项目,用于分别充当“生产者”与“消费者”角色,最终通过redisson的“服务调度组件”实现服务与服务之间、接口与接口之间的调用!  课程收益: (1)认识并掌握redisson为何物、常见的几种典型数据结构-分布式对象、集合、服务的应用及其典型应用场景的实战; (2)掌握如何基于spring boot2.0整合redisson搭建企业级多模块项目,并以此为奠基,实战企业级应用系统中常见的业务场景,巩固相应的技术栈! (3)站在项目管理与技术精进的角度,掌握对于给定的功能模块进行业务流程图的绘制、分析、模块划分、代码实战与性能测试和改进,提高编码能力与其他软实力; (4)对于Java微服务、分布式、springboot精进者而言,学完本课程,不仅可以巩固提高中间件的实战能力,其典型的应用场景更有助于面试、助力相关知识点的扫盲! 如下图所示: 关键字:Spring Boot,Redis,缓存穿透,缓存击穿,缓存雪崩,红包系统,Mybatis,高并发,多线程并发编程,发送邮件,列表List,集合Set,排行榜,有序集合SortedSet,哈希Hash ,进阶实战,面试,微服务、分布式 适用人群:redisson学习者,分布式中间件实战者,微服务学习者,java学习者,spring boot进阶实战者,redis进阶实战者
### 回答1: Spring Boot集成Redis可以使用Spring Data Redis。Spring Data Redis是Spring Data的一部分,它提供了对Redis的支持,包括对Redis的连接、操作、数据序列化等。 以下是使用Spring Boot集成Redis缓存的步骤: 1. 添加Spring Data RedisRedis客户端依赖 在Maven中添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> </dependency> ``` 2. 配置Redis连接信息 在application.properties中添加以下配置: ```properties spring.redis.host=localhost spring.redis.port=6379 ``` 3. 配置Redis缓存管理器 在Java配置类中添加以下代码: ```java @Configuration @EnableCaching public class CacheConfig { @Bean public RedisConnectionFactory redisConnectionFactory() { return new JedisConnectionFactory(); } @Bean public RedisTemplate<String, Object> redisTemplate() { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory()); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer()); return redisTemplate; } @Bean public CacheManager cacheManager() { RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate()); cacheManager.setDefaultExpiration(600); return cacheManager; } } ``` 4. 在需要缓存的方法上添加@Cacheable注解 例如: ```java @Service public class UserService { @Autowired private UserRepository userRepository; @Cacheable(value = "userCache", key = "#id") public User getUserById(Long id) { Optional<User> optionalUser = userRepository.findById(id); return optionalUser.orElse(null); } } ``` @Cacheable注解会将方法的返回值缓存Redis中,value属性指定缓存的名称,key属性指定缓存的键。 以上就是使用Spring Boot集成Redis缓存的步骤。注意,这里使用了默认的Redis连接工厂和Redis模板,如果需要更多的定制化配置,可以参考Spring Data Redis文档进行设置。 ### 回答2: Spring Boot 是一个用于快速构建 Java 应用程序的开源框架。它简化了基于 Spring 框架的应用程序的创建和配置过程。而 Redis 是一种快速且高效的内存数据库,用于存储和检索数据。 在 Spring Boot 中使用 Redis 缓存可以提高应用程序的性能和响应速度。要使用 Redis 缓存,首先需要在项目的依赖中添加 Redis 相关的依赖项。然后,在应用程序的配置文件中配置 Redis 的连接信息,包括主机名、端口号、密码等。 一旦配置完成,就可以在应用程序中使用 @Cacheable 注解将方法标记为可缓存的。当调用被标记为缓存的方法时,Spring Boot 会首先检查缓存中是否已经存在该数据,如果存在则直接返回缓存中的数据,否则执行方法并将结果存入缓存。可以使用 @CacheEvict 注解来清除缓存中的数据,以便在数据发生变化时及时更新缓存。 使用 Redis 缓存还可以有其他一些高级特性,例如设置缓存的过期时间、使用不同的缓存键生成策略等。还可以通过配置 Redis 集群实现高可用和负载均衡。 总而言之,Spring Boot 提供了简单而强大的工具来集成 Redis 缓存,通过使用 Redis 缓存可以提高应用程序的性能和可伸缩性,减轻后端数据库的负载,从而提供更好的用户体验。 ### 回答3: Spring Boot使用Redis作为缓存的步骤如下: 1. 导入Redis依赖:在pom.xml文件中添加Spring Boot对Redis的依赖。 2. 配置Redis连接信息:在application.properties或application.yml文件中配置Redis的连接信息,包括主机名、端口号、密码等。 3. 创建RedisTemplate Bean:在Spring Boot的配置类中创建RedisTemplate Bean,用于操作Redis数据库。 4. 使用RedisTemplate进行缓存操作:在需要使用缓存的方法上添加注解@EnableCaching,然后在方法执行时,使用RedisTemplate进行缓存的读取和写入操作。 5. 添加缓存注解:在需要进行缓存的方法上添加注解@Cacheable,用于标记此方法的结果需要被缓存。可以通过设置缓存的key,来定制不同参数下的缓存策略。 6. 清除缓存:在需要清除缓存的方法上添加注解@CacheEvict,用于标记此方法执行后需要清除缓存。 通过以上步骤,Spring Boot就可以和Redis进行连接,并使用Redis作为缓存来提高应用程序的性能。在缓存读取时,先从Redis中获取数据,如果Redis中不存在,则从数据库中读取,然后将读取到的数据写入Redis中;在缓存写入时,先将数据写入Redis中,再同步写入数据库。这样可以大大提高读取数据的速度,并减轻数据库的压力。同时,Spring Boot提供了灵活的缓存策略配置,可以根据业务需求来定制缓存的命中规则和过期时间。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值