Redis无侵入式地缓存业务查询数据

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Allen_jinjie/article/details/79094054

这里是根据我们自己的业务特点(极少数据更新且不要求数据精确,某些查询的时间又比较长),我们采用了 Redis 做缓存,使用 Hash 数据结构缓存数据。

我们的业务查询都是通过 Service 层整合多个 DAO 完成 DTO 的组装,基于业务特点,没必要将各个 DAO 的数据缓存,而是直接缓存 Service 的最终 DTO 结果。

首先,在 Spring Boot 里实例化 RedisTemplate:

@Configuration
public class RedisConfig {	
	private static final Logger logger = Logger.getLogger(RedisConfig.class);
	
	@Bean
	public RedisConnectionFactory genFactory(){
		JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
		jedisConnectionFactory.setHostName("192.168.1.82");
		jedisConnectionFactory.setUsePool(true);
		return jedisConnectionFactory;
	}
	
	@Bean
	public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory){
		logger.info("进入 RedisConfig.redisTemplate() 方法。。。。。。。。。。。。");
		RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
		redisTemplate.setKeySerializer(new StringRedisSerializer());
		redisTemplate.setHashKeySerializer(new StringRedisSerializer());
		redisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
		redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
		redisTemplate.setConnectionFactory(factory);
		return redisTemplate;
	}
}

当然,pom.xml 文件得加上 Redis 依赖:

<dependency>  
	<groupId>org.springframework.boot</groupId>  
	<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency> 
然后,定义一个注解,凡是希望数据被缓存的 Service.get**方法上都加上这个注解:
@Documented//文档  
@Retention(RetentionPolicy.RUNTIME)//在运行时可以获取  
@Target(ElementType.METHOD)//作用到类,方法,接口上等
public @interface CurieCache {
}
比如我们想缓存下面这个查询结果,就直接加上注解:
@CurieCache
public CohortDefinitionDTO getCohortProcessSummaryById(Integer defId){					
	List<ConceptData> datas = new ArrayList<ConceptData>();
	...
}
最后,让缓存起作用,就看 Around Advice 了,详细解释已经在该类的注释上了:

import java.lang.reflect.Method;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

/**
 * 1. 使用 Redis 的 Hash 缓存 Service 层的查询结果
 * 2. Key 使用类名 + 方法名, 
 * 3. 任一 field 的值使用参数的String字符串连接,如果无参数,就使用默认值
 * 4. 希望结果被缓存的get**方法只需要加上自定义的 CurieCache 注解,就会被拦截:
 * 		a. 如果缓存里有就直接从缓存里拿数据
 * 		b. 否则先执行业务查询,最终结果在返回前放入缓存
 * @author Allen
 */
@Component
@Aspect
public class RedisAdvice {
	private Logger logger = LoggerFactory.getLogger(RedisAdvice.class);
	
	@Autowired
	private RedisTemplate<String, Object> redisTemplate;
	
	@Around("execution(* com.hebta.curie.service.*Service.get*(..))")  
    public Object aroundMethod(ProceedingJoinPoint pjp) throws Throwable {
		MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
		Method method = methodSignature.getMethod();		
		String key = null;
		String field = null;
		if (method.isAnnotationPresent(CurieCache.class)){
			logger.info("当前方法设置了CurieCache  注解");
			String target = pjp.getTarget().toString();
			StringBuilder kSb = new StringBuilder();
			kSb.append(target.substring(target.lastIndexOf(".") + 1, target.indexOf("@")))
				.append(":").append(method.getName());
			key = kSb.toString();
			
			logger.info("target is : {}, key is : {}", target, key);
			
			if (pjp.getArgs().length > 0) {
				logger.info("方法 {} 无参数", method.getName());
				StringBuilder sb = new StringBuilder();
				for (Object obj : pjp.getArgs()) {
					sb.append(obj.toString());
				}
				field = sb.toString();
			} else {
				field = "blank";
			}
			logger.info("field is : {}", field);
			
			if (redisTemplate.opsForHash().hasKey(key, field)){
				logger.info("缓存里有该结果,直接从缓存里取");
				return redisTemplate.opsForHash().get(key, field);
			} else {
				logger.info("没有缓存该结果,先计算,存入缓存,再返回");
				Object result = pjp.proceed();
				redisTemplate.opsForHash().put(key, field, result);
				return result;
			}
		} else {
			logger.info("无 CurieCache  注解");
			return pjp.proceed();
		}		
	}
}




猜你喜欢

转载自blog.csdn.net/Allen_jinjie/article/details/79094054