摘要: 主要针对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缓存的更多相关文章

  1. spring cloud: Hystrix(六):feign的注解@FeignClient:fallbackFactory(类似于断容器)与fallback方法

    fallbackFactory(类似于断容器)与fallback方法 feign的注解@FeignClient:fallbackFactory与fallback方法不能同时使用,这个两个方法其实都类似 ...

  2. 【译】Spring 4 + Hibernate 4 + Mysql + Maven集成例子(注解 + XML)

    前言 译文链接:http://websystique.com/spring/spring4-hibernate4-mysql-maven-integration-example-using-annot ...

  3. Spring框架之使用JdbcTemplate开发Dao层程序

    简介: JdbcTemplate开发dao层程序     由Spring框架给我们提供,Spring提供的很多操作数据源(关系型数据库,二维表格模型,有明确的行和列(mysql/orcal等) 非关系 ...

  4. Junit结合Spring对Dao层进行单元测试

    关于单元测试,上一次就简单的概念和Mock基础做了,参考:http://60.174.249.204:8888/in/modules/article/view.article.php/74 实际开发过 ...

  5. Spring Boot 2.X(六):Spring Boot 集成Redis

    Redis 简介 什么是 Redis Redis 是目前使用的非常广泛的免费开源内存数据库,是一个高性能的 key-value 数据库. Redis 与其他 key-value 缓存(如 Memcac ...

  6. spring boot / cloud (十六) 分布式ID生成服务

    spring boot / cloud (十六) 分布式ID生成服务 在几乎所有的分布式系统或者采用了分库/分表设计的系统中,几乎都会需要生成数据的唯一标识ID的需求, 常规做法,是使用数据库中的自动 ...

  7. Spring详解(六)------AOP 注解

    上一篇博客我们讲解了 AspectJ 框架如何实现 AOP,然后具体的实现方式我们是通过 xml 来进行配置的.xml 方式思路清晰,便于理解,但是书写过于麻烦.这篇博客我们将用 注解 的方式来进行 ...

  8. Spring Boot 学习笔记(六) 整合 RESTful 参数传递

    Spring Boot 学习笔记 源码地址 Spring Boot 学习笔记(一) hello world Spring Boot 学习笔记(二) 整合 log4j2 Spring Boot 学习笔记 ...

  9. [Spring Cloud实战 | 第六篇:Spring Cloud Gateway+Spring Security OAuth2+JWT实现微服务统一认证授权

    一. 前言 本篇实战案例基于 youlai-mall 项目.项目使用的是当前主流和最新版本的技术和解决方案,自己不会太多华丽的言辞去描述,只希望能勾起大家对编程的一点喜欢.所以有兴趣的朋友可以进入 g ...

随机推荐

  1. IntelliJ IDEA安装ideaIU-2019.1

  2. JSP项目前端优化

    问题:在谷歌浏览器中兼容问题,在点击超链接第一次会跳到头部,第二次点击才能打开的问题. 解决方案:是href的问题,删除href的属性,使用click事件,并添加a的超链接样式. #othera{ c ...

  3. echarts 隐藏Y轴最大最小值label及分割线 ----障眼大发好使

    需求图 1====>label 最大最小值还好弄, yAxis{ axisLabel{ showMinLabel: false, showMaxLabel: false, }} 2====> ...

  4. javascript封装函数入门

    封装函数的入门 一.使用函数有两步: 1.定义函数,又叫声明函数, 封装函数. 定义函数的三个要素:功能,参数,返回值. function 函数名(形参){ 函数代码 return 结果} //2.调 ...

  5. HDU 1060  Leftmost Digit

    Leftmost Digit Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) T ...

  6. MySQL 常用命令(Linux)

    一.查看MySQL服务 MySQL服务应该随开机自动启动的.正常情况下,查看开机自动启动的服务使用chkconfig命令,如下: chkconfig --list 实际mysql是否真正启动,是否真正 ...

  7. RabbitMQ 实现远程过程调用RPC

    RPC调用的顺序1. 在客户端初始化的时候,也就是SimpleRpcClient类初始化的时候,它会随机的创建一个callback队列,用于存放服务的返回值,这个队列是exclusive的.连接断开就 ...

  8. codeforces 1110F

    题解: 正解做法比较简单,考虑离线之后,相邻两个节点之间的答案是有关系的 发现从父亲移到儿子后,改变的距离对于当前节点子树内和子树外的是一样的 所以线段树维护一下区间加减取max就可以了 另外的做法1 ...

  9. CMD运行命令每次都要进入很麻烦

    20:35:52 win+r  输入regedit 进入注册表 找到HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor项 创建AutoRun ...

  10. Game 23

    Polycarp plays "Game 23". Initially he has a number nn and his goal is to transform it to  ...