• Redeis缓存查询基于元注解与AOP结合使用——不过时的优雅


    Redeis缓存查询基于元注解与AOP结合使用

    根据优化需要,数据查询的时候无法避免的使用Redis基于缓存查询,进而减少对于数据库的查询压力,对于过多的方法基于缓存存储,为提高代码的复用性,采用一种不过时的写法。

    整体的逻辑是 根据key对应查询Redis 获取缓存信息,如果key值不存在,则对应字节在原方法中调用 直接进入数据库进行查询,通过jedis进行存入到Redis中。

    元注解

    描述注解的注解 就是元注解
    此处可以理解为 自定义注解 进行对原注解的扩展

    元注解:

    1. @Target 定义Annotation 所修饰的对象范围 作用域类或者接口上
    2. @Retention 定义Annotation 保留时间
    3. @Documented 被修饰的注解可以被文档化
    4. @Inherited 定义该注解效果是否能被注解修饰的子类所拥有

    自定义注解:

    @Target(ElementType.METHOD) // 表示作用于方法
    @Retention(RetenionPolicy.RUNTIME)// 表示运行时即效
    public @interface CacheFind{
    	public String key() defalut "";
    	public String seconds() defalut 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    此时对应于 注解CacheFind 就可以应用于对应的方法上,只不过目前还未做对应的方法实现功能。对应结合AOP 声明对应的切面,进行功能逻辑的扩展。

    AOP

    • 切面aspect 横切对象 一般为一个具体的类对象
    • 通知advice 切面的某个特定的连接点上执行的动作
    • 连接点 joinpoint 程序执行过程中某个特定的点 一般指拦截到的方法
    • 切入点poincut 对多个连接点(joinpoint) 一种定义 一般可以理解为多个连接点的集合

    在这里插入图片描述

    @Around

    Bean 用于指定bean对象的所有方法

    Within 用于匹配指定包下所有的类

    Execution用于按照指定语法规则匹配到具体的方法

    Annotation 用于指定注解修饰的方法

    对应的切面
    使用自定义注解,实现Redis的查询扩充

    
    @Aspect
    @Component
    public calss RedisAop{
    	Private static final ObjectMapper mapper = new ObjectMapper();
    	
    	@Autowired
    	private Jedis jedis;
    	
    	@Around("@annotation(cachefind)") 
    	public Object around(ProceedingJoinPoint joinPoint,CacheFind cachefind){
    		String key =getKey(joinPoint,cacheFind);
    		String json=jedis.get(key);
    		Object returnObject=null;
    		if(StringUtils.isEmpty(json)){
    			//  如果此处数据 不存在于Redis缓存中  则直接执行原方法 直接进行数据库的查询	
    			try{
    				returnObject=joinPoint.proceed();
    				String objJSON=mapper.writeValueAsString(returnObject);
    				//  对应reids中的超时时间 判断是否指定还是默认
    				if(cacheFind.seconds>0){
    					jedis.setex(key,chacheFind.seconds,objJSON);
    				}else{
    					jedis.set(key,objJSON);
    				}
    			}catch(Throwable e){
    				e.printStackTrace();
    				throw new RuntimeException();
    			}
    		}else{
    		// 获取返回对象的字节码
    		Class<?> targetClass=getClass(joinPoint);
    		// 此处的转换需要 进行将json转换为java 然后返回
    			returnObject=mapper.readValue(json,targetClass);
    		}
    		return returnObject
    	
    	}
    	private String getKey(ProceedingJoinPoint joinPoint,CacheFind cachefind){
    		if(!StringUtils.isEmpty(cacheFind.key())){
    			return cacheFind.key();
    		}
    		String className = joinPoint.getSignature().getDeclaringTypeName();
    		String methodName= joinPoint.getStignature().getName();
    		String firstArg= joinPoint.getArgs()[0].toString();
    		return className+methodName+"::"+firstArgs;
    	}
    
    	private Class<?> getClass(ProceedingJoinPoint joinPoint){
    		MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
    		return methodSignature.getReturenType();
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
  • 相关阅读:
    容器基础篇
    医院管理系统数据库,课程设计,SQLserver,纯代码设计
    课题学习(七)----粘滑运动的动态算法
    软件测试 -- 进阶 2 软件测试分析
    【前端开发】JS Vue React中的通用递归函数
    EFK(elasticsearch+filebeat+kibana)日志分析平台搭建
    多肽介导PEG磷脂——靶向功能材料之DSPE-PEG-RGD/TAT/NGR/APRPG
    Java8函数式编程-lambda表达式与stream流
    数据结构初阶 · 链式二叉树的部分问题
    优先队列使用
  • 原文地址:https://blog.csdn.net/acwing/article/details/128016641