自定義Redis緩存注解的實現
我們在Spring的框架中,可以使用注解的形式(@EnableCache和@Cacheable)來實現對查詢的數據進行Redis的緩存,我們自己其實也可以自定義一個緩存注解來實現redis緩存的功能。
編寫自定義緩存注解
首先,我們要自定義一個Redis緩存注解,之后要將該注解標注到對應的方法上去,代碼如下:
/**
* 對方法啟用Redis緩存,使其具有方法前判斷緩存,方法后如果沒有緩存則存儲Redis緩存
* 緩存key的格式為:value::key,具體的數值由用戶傳遞的注解參數來提供
* @author young
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyRedisCacheable {
/**
* Redis緩存key的前綴
* @return
*/
String value() default "";
/**
* Redis緩存key的后綴
* @return
*/
String key() default "";
}
編寫具體AOP代理方法類
注解只是用來標注當前的方法要用來做什么,同時傳遞相應操作所需要的參數信息。具體要在標注的方法前后實現什么功能,還需要通過Spring AOP的面向切面編程來實現對方法前后所需要進行的處理。具體代碼如下:
/**
* MyRedisCacheable注解的具體處理類,實現對標注方法執行前做Redis緩存檢查處理,方法執行后執行緩存Redis數據的處理
* @author young
*/
@Component
@Aspect
public class CacheAspect {
private Logger logger = LoggerFactory.getLogger(CacheAspect.class);
@Autowired
private RedisTemplate redisTemplate;
/**
* 設置注解的切入點,即指定切入的方法為
*/
@Pointcut("@annotation(com.young.redis.aop.MyRedisCacheable)")
public void cachePointcut(){
}
/**
* 定義需要進行AOP切面編程的切點是哪個,也即標注MyRedisCacheable注釋的方法
* @param proceedingJoinPoint 當前切入方法的上下文
* @return
*/
@Around("cachePointcut()")
public Object doRedisCache(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Object value = null;
try {
//獲取切入方法的標簽
MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
//通過該標簽來獲取修飾的方法和方法參數
Method method = proceedingJoinPoint.getTarget().getClass().
getMethod(signature.getName(),signature.getMethod().getParameterTypes());
//獲取當前方法的注解以及注解的參數
MyRedisCacheable myRedisCacheable = method.getAnnotation(MyRedisCacheable.class);
//redis key的EL表達式
String keyEL = myRedisCacheable.key();
//redis key的前綴
String prifix = myRedisCacheable.value();
//解析EL表達式
ExpressionParser expressionParser = new SpelExpressionParser();
Expression expression =expressionParser.parseExpression(keyEL);
//用來組合EL表達式和方法參數的EL上下文對象
EvaluationContext evaluationContext = new StandardEvaluationContext();
//獲取方法的參數,將參數放入evaluationContext
Object[] args = proceedingJoinPoint.getArgs();
DefaultParameterNameDiscoverer defaultParameterNameDiscoverer = new DefaultParameterNameDiscoverer();
String[] parameterNames = defaultParameterNameDiscoverer.getParameterNames(method);
for (int i = 0; i < parameterNames.length; i++) {
evaluationContext.setVariable(parameterNames[i],args[i].toString());
}
//使用Expression和EvaluationContext來解析EL表達式
String cacheKey = prifix + "::" + expression.getValue(evaluationContext).toString();
//判斷緩存是否存在
value = redisTemplate.opsForValue().get(cacheKey);
if(value != null){
logger.info("從緩存中讀取到的key:" + cacheKey +",value:" + value);
return value;
}
//不存在則執行數據庫方法進行查詢
value = proceedingJoinPoint.proceed();
//將查詢到的內容存到Redis
redisTemplate.opsForValue().set(cacheKey,value);
}catch (Throwable throwable){
throwable.printStackTrace();
}
//方法執行后返回查詢結果
return value;
}
}
編寫配置類
無論是在SpringMvc框架還是Springboot框架中,都可以通過編寫配置類的方式來配置需要加載的bean對象,具體的配置類代碼如下:
/**
* 通過注解的形式來配置spring中的bean
* 使用自定義注解方式來實現Redis緩存
* @author young
*/
@Configuration
@EnableAspectJAutoProxy //開啟AOP自動代理
public class AppConfig {
/**
* 通過注釋來獲取properties配置文件中的自定義值,引號里邊為EL表達式
*/
@Value("${spring.redis.host}")
String host;
@Value("${spring.redis.port}")
int port;
/**
* 通過RedisConnectionFactory來獲取RedisTemplate,從而進行Redis的相關操作(注解方式同樣需要)
* @return
*/
@Bean
public RedisConnectionFactory redisConnectionFactory(){
//配置Redis的主機和端口
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setHostName(host);
redisStandaloneConfiguration.setPort(port);
//
RedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory(redisStandaloneConfiguration);
return redisConnectionFactory;
}
/**
* 加載RedisTemplate bean
* @param redisConnectionFactory
* @return
*/
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory){
RedisTemplate redisTemplate = new RedisTemplate();
redisTemplate.setConnectionFactory(redisConnectionFactory);
//指定Redis序列化的方式
redisTemplate.setKeySerializer(StringRedisSerializer.UTF_8);
return redisTemplate;
}
}
這樣,一個自定義Redis緩存注解的實現也就基本完成了,這對於我們了解注解的底層原理也是很有幫助的。