深入理解Spring Redis的使用 (六)、用Spring Aop 实现注解Dao层的自动Spring Redis缓存
摘要: 主要针对Dao层的一些数据库查询的操作,数据实时性不强,直接加入缓存。当缓存中有的时候,就使用缓存中的数据。这样的方法,最终仅仅使用一个注解实现。对于之前的hibernate二级缓存使用,比较陌生。比如是否支持Redis或者可以自己开发支持。是否支持针对部分需要加入缓存的方法配置,而不是所有的hibernate实体都加入缓存。可能我这种方法对于二级缓存来说,抛开代码差距,也是殊途同归的东西。
这几天工作中,突然遇到了对于有些个实体类,需要被缓存起来。但是这些个实体类数目庞大, 初始化加载的话,太耗费时间。所以初步的方案就是先查缓存,缓存没有就查询数据库,查完数据库再放入缓存。同时也方便设置过期时间。
但是针对目前的项目来说,Dao是作为独立的Maven Module,Redis也是独立的Maven Module,相互耦合的话,代码变得难以维护,结构不清晰。所以引入了注解,然后在Redis项目中,针对注解做AOP,这样的话,没有用到缓存的项目,就可以忽略这样的注解。如果用到了,可以自动加入缓存。
注解代码:
package com.ns.annotation; import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.concurrent.TimeUnit;
/**
* 只能注解dao里面对应的get方法,传递的参数作为hashkey,返回的值作为value
* @author Han
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Cached {
/**
* redis key
* @return
*/
String key();
/**
* 过期时间,默认为0即永不过期
* @return
*/
long timeout() default 0L;
/**
* 时间单位,默认为秒
* @return
*/
TimeUnit timeunit() default TimeUnit.SECONDS; }
Aop切面代码
package com.ns.redis.aop; import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map; import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.ArrayUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert; import com.ns.annotation.Cached;
import com.ns.redis.dao.base.BaseRedisDao;
/**
* 对dao的getbean的缓存处理
* @author Han
*/
@Aspect
@Component
public class AutoRedisCached extends BaseRedisDao<String, Object>{ /*
* 约束任意包下的包含Dao的类的任意方法,并且被cached注解
*/
@Pointcut("execution(* *..*Dao*.*(*,..) && @annotation(com.ns.annotation.Cached))")
private void cacheMethod(){} @Around("cacheMethod()")
public Object doArround(ProceedingJoinPoint pjp) throws Throwable{
Object[] args = pjp.getArgs();
//定义序列化器
final RedisSerializer<String> keySerializer = getKeySerializer();
final RedisSerializer<Object> hashValueSerializer = getHashValueSerializer();
final RedisSerializer<Object> hashKeySerializer = getHashKeySerializer(); //序列化参数,作为hashkey
byte [] hashkeyBytesTmp = null;
if(args.length == 1){
hashkeyBytesTmp = hashKeySerializer.serialize(args[0]);
}else{
hashkeyBytesTmp = new byte[0];
for(Object arg : args){
hashkeyBytesTmp = ArrayUtils.addAll(hashkeyBytesTmp, hashKeySerializer.serialize(arg));
}
} final byte [] hashkeyBytes = hashkeyBytesTmp; MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
Method method = methodSignature.getMethod();
final Cached cacheinfo = method.getAnnotation(Cached.class);
Object obj= null; obj = execute(new RedisCallback<Object>() {
@Override
public Object doInRedis(RedisConnection connection) throws DataAccessException {
byte [] tmp = connection.hGet(keySerializer.serialize(cacheinfo.key()), hashkeyBytes);
return hashValueSerializer.deserialize(tmp);
}
});
if(obj == null){
final Object objReturn = pjp.proceed();
if(objReturn != null){
execute(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
return connection.hSet(keySerializer.serialize(cacheinfo.key()), hashkeyBytes,hashValueSerializer.serialize(objReturn));
}
}); if(cacheinfo.timeout()>0){
expire(cacheinfo.key(), cacheinfo.timeout(), cacheinfo.timeunit());
}
}
obj = objReturn;
}
//从dao获取
return obj;
}
}
深入理解Spring Redis的使用 (六)、用Spring Aop 实现注解Dao层的自动Spring Redis缓存的更多相关文章
- spring cloud: Hystrix(六):feign的注解@FeignClient:fallbackFactory(类似于断容器)与fallback方法
fallbackFactory(类似于断容器)与fallback方法 feign的注解@FeignClient:fallbackFactory与fallback方法不能同时使用,这个两个方法其实都类似 ...
- 【译】Spring 4 + Hibernate 4 + Mysql + Maven集成例子(注解 + XML)
前言 译文链接:http://websystique.com/spring/spring4-hibernate4-mysql-maven-integration-example-using-annot ...
- Spring框架之使用JdbcTemplate开发Dao层程序
简介: JdbcTemplate开发dao层程序 由Spring框架给我们提供,Spring提供的很多操作数据源(关系型数据库,二维表格模型,有明确的行和列(mysql/orcal等) 非关系 ...
- Junit结合Spring对Dao层进行单元测试
关于单元测试,上一次就简单的概念和Mock基础做了,参考:http://60.174.249.204:8888/in/modules/article/view.article.php/74 实际开发过 ...
- Spring Boot 2.X(六):Spring Boot 集成Redis
Redis 简介 什么是 Redis Redis 是目前使用的非常广泛的免费开源内存数据库,是一个高性能的 key-value 数据库. Redis 与其他 key-value 缓存(如 Memcac ...
- spring boot / cloud (十六) 分布式ID生成服务
spring boot / cloud (十六) 分布式ID生成服务 在几乎所有的分布式系统或者采用了分库/分表设计的系统中,几乎都会需要生成数据的唯一标识ID的需求, 常规做法,是使用数据库中的自动 ...
- Spring详解(六)------AOP 注解
上一篇博客我们讲解了 AspectJ 框架如何实现 AOP,然后具体的实现方式我们是通过 xml 来进行配置的.xml 方式思路清晰,便于理解,但是书写过于麻烦.这篇博客我们将用 注解 的方式来进行 ...
- Spring Boot 学习笔记(六) 整合 RESTful 参数传递
Spring Boot 学习笔记 源码地址 Spring Boot 学习笔记(一) hello world Spring Boot 学习笔记(二) 整合 log4j2 Spring Boot 学习笔记 ...
- [Spring Cloud实战 | 第六篇:Spring Cloud Gateway+Spring Security OAuth2+JWT实现微服务统一认证授权
一. 前言 本篇实战案例基于 youlai-mall 项目.项目使用的是当前主流和最新版本的技术和解决方案,自己不会太多华丽的言辞去描述,只希望能勾起大家对编程的一点喜欢.所以有兴趣的朋友可以进入 g ...
随机推荐
- django实现SSO
前言 公司的各种运维平台越来越多,用户再每个平台都注册账号,密码,密码太多记不住不说,然后有的平台过一段时间还得修改密码,烦!还不如弄个统一登录平台!! 需求分析 造这辆大车,首先就得造两个轮子 首先 ...
- trie字典树:初学
应用: 1.前缀问题 2.异或问题(转化为前缀问题) 3.查询问题 思想: 将要进行匹配的字符串化为一颗树 字符为边,在结束位置统计该串的全部信息 操作:插入,查询,删除.etc ac: #inclu ...
- Canvas中如何画一条清晰的线宽为奇数(如1px逻辑像素)的线?
我在开发中使用canvas的机会不是很多,但是第一次实际使用中就遇到了问题,"很久很久以前,我自己画了一个雷达图,线宽都是1像素,但是显示效果不如期望,这才发现canvas中的画线还是有坑的 ...
- Taro父子组件通信
父组件 testEvent = () =>{ console.log('abc123') } <Test test={1231323} onTestEvent={this.testEven ...
- 前端工具mock的使用 - 造数据模拟网络请求
前后端同步开发过程中,有时候前端页面完成了,需要等待后端接口完成部署后才能联调. 这个时候如果不想等待,想自己造数据模拟网络请求,这种情况就能用到mock工具了. mock工具可以用在web网站,也能 ...
- java-数组排序--冒泡排序、鸡尾酒排序、地精排序
冒泡排序 冒泡排序的思想是,让依次数组中相邻的数进行比较,如果前一个数比后一个数大,则两数进行交换,大的数就会象泡泡一样慢慢浮在水面上了 见图解 稳定性:稳定时间复杂度:O(n2) public st ...
- 将source类中的属性值赋给target类中对应的属性
/** * 对象的属性值拷贝 * <p> * 将source对象中的属性值赋值到target对象中的属性,属性名一样,类型一样 * <p> * example: * <p ...
- redis对string进行的相关操作
redis对string类型操作的相关命令以及如何在python使用这些命令 redis对string类型操作的命令: 命令 语法 概述 返回值 Redis SET 命令 set key value ...
- Candies POJ - 3159 (最短路+差分约束)
During the kindergarten days, flymouse was the monitor of his class. Occasionally the head-teacher b ...
- SQL Server 分区表上建立ColumnStore Index 如何添加新分区方法与步骤
在生产环境中会遇到这样的场景,一个表随着时间的推移,越来越大,这个时候我们开始动手为这个表建立分区来改进查询性能. 但是表过大上百个G的时候,在数据仓库中,为了改进查询性能,我们可以添加在分区表的基础 ...