缓存服务器Redis 04 AOP实现Redis缓存服务

史湘云
• 阅读 1216

在上文中,我们虽然在业务层service中完成了代码的实现.但是该代码不具有复用性.如果换了其他的业务则需要重新编辑.
并且由于缓存的代码写在业务层service中,所以代码的耦合性高,不方便以后的扩展.
所以我们从代码复用以及降低代码的耦合性的方面使用AOP来实现redis缓存.

AOP

AOP即面向切面编程--在不改动原有代码的基础上,对业务进行增强.
AOP = 切入点表达式 + 通知方法

专业术语:
1.连接点: 在执行正常的业务过程中满足了切入点表达式时进入切面的点.(织入) 多个
2.通知: 在切面中执行的具体的业务(扩展) 方法
3.切入点: 能够进入切面的一个判断 if判断 一个
4.目标方法: 将要执行的真实的业务逻辑.

通知方法

分类:
1.前置通知(@Before): 目标方法执行之前执行
2.后置通知(@After): 目标方法执行之后执行
3.异常通知(@AfterThrowing): 目标方法执行之后抛出异常时执行
4.最终通知(@AfterReturning): 不管什么时候都要执行的方法.
说明:上述的四大通知类型不能控制目标方法是否执行.一般使用上述的四大通知类型,都是用来记录程序的执行状态.
5.环绕通知(@Around): 在目标方法执行前后都要执行的通知方法. 控制目标方法是否执行.并且环绕通知的功能最为强大.
环绕通知是最为常用的.

切入点表达式

分类:
1.bean(bean的id) 类名首字母小写 匹配1个类
2.within(包名.类名) 按包路径匹配类 匹配多个类
上述表达式是粗粒度的控制,按类匹配.
3.execution(返回值类型 包名.类名.方法名(参数列表))
4.@annotation(包名.注解名) 按注解进行拦截.
上述是细粒度的控制.
bean和@annotation较为常用

实现Redis缓存

业务分析

1.自定义注解CacheFind 主要被注解标识的方法,则开启缓存的实现.
2.为了将来区分业务,需要在注解中标识key属性,由使用者自行填写.
3.为了用户提供数据超时功能.

自定义注解@CacheFind

@Retention(RetentionPolicy.RUNTIME) //该注解运行时有效
@Target({ElementType.METHOD})       //对方法有效
public @interface CacheFind {
    String key();               //该属性为必须添加
    int seconds() default 0;    //设定超时时间 默认不超时
}

编写CacheAOP类

package com.jt.aop;  
  
import com.jt.annotation.CacheFind;  
import com.jt.util.ObjectMapperUtil;  
import org.aspectj.lang.JoinPoint;  
import org.aspectj.lang.ProceedingJoinPoint;  
import org.aspectj.lang.Signature;  
import org.aspectj.lang.annotation.Around;  
import org.aspectj.lang.annotation.Aspect;  
import org.aspectj.lang.annotation.Before;  
import org.aspectj.lang.annotation.Pointcut;  
import org.aspectj.lang.reflect.MethodSignature;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.stereotype.Component;  
import org.springframework.util.StringUtils;  
import redis.clients.jedis.Jedis;  
  
import java.util.Arrays;  
  
@Component  
@Aspect  
public class RedisAOP {  
 //注入缓存reids对象  
 @Autowired  
 private Jedis jedis;  
 
 //@Pointcut("@annotation(com.jt.annotation.CacheFind)")  
 //public void doRedisPointCut(){}  
 /**  
 * 拦截@CacheFind注解表示的方法  
 * 通知选择: 缓存的实现应该选用环绕通知  
 * 步骤:  
 *  1.动态生成key 用户填写的key+用户提交的参数  
 */  
 @Around("@annotation(cacheFind)")  
    public Object around(ProceedingJoinPoint joinPoint, CacheFind cacheFind){  
        try {  
            Object result = null;  
 //1.如何动态获取用户在注解中填写的数据  
 String prekey = cacheFind.key();  
 //2.动态获取目标方法中的参数  将数组转化为字符串  
 String args = Arrays.toString(joinPoint.getArgs());  
 String key = prekey + "::" + args; //"ITEM_CAT_PARENTID::[0]"  
 //3.查询缓存中查询  
 //4.判断json中是否有值  
 if (jedis.exists(key)) {  //先获取json数据  
 String json = jedis.get(key);  
 //动态获取目标方法的返回值类型?? 向上造型 不用强转   向下造型  
 MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();  
 Class target = methodSignature.getReturnType();  
 //7.进入代表程序中有值,将json转为对象  
 result = ObjectMapperUtil.toObject(json, target);  
 System.out.println("AOP实现缓存查询!!!!");  
 }else {  
                //5.若缓存中没有查询数据库  
 result = joinPoint.proceed(); //执行目标方法,获取返回值结果  
 System.out.println("AOP执行数据库操作");  
 //6.将数据存到redis中  
 //先转为json格式  
 String json = ObjectMapperUtil.toJSON(result);  
 if(cacheFind.seconds()>0){  //判断是否需要超时时间  
 jedis.setex(key, cacheFind.seconds(), json);  
 }else {  
                    jedis.set(key, json);  
 }  
            }  
            return result;  
 }catch (Throwable e){  
            e.printStackTrace();  
 throw new RuntimeException(e);  
 }  
    }  
}

注意

关于环绕通知参数的说明:
1.连接点必须位于通知方法参数的第一位
2.其他四大通知类型不可以添加ProceedingJoinPoint对象,可以添加JointPoint对象

JoinPoint使用

 /**
     * 要求: 拦截注解方法
     * 打印:
     *      1.打印目标对象的类型
     *      2.打印方法的参数
     *      3.获取目标对象的名称及方法的名称
     * @param joinPoint
     */
    @Before("@annotation(com.jt.anno.CacheFind)")
    public void before(JoinPoint joinPoint){

        Object target = joinPoint.getTarget();  //获取目标对象
        Object[] args = joinPoint.getArgs();    //获取方法参数的
        String targetName =
                joinPoint.getSignature().getDeclaringTypeName(); //获取目标对象的名称
        //获取目标对象的类型
        Class targetClass = joinPoint.getSignature().getDeclaringType();
        //获取目标方法的名称
        String methodName = joinPoint.getSignature().getName();
        System.out.println(target);
        System.out.println(args);
        System.out.println(targetName);
        System.out.println(targetClass);
        System.out.println(methodName);

    }
点赞
收藏
评论区
推荐文章
带我的粉丝们一起揭秘spring aop底层原理及实现
实在是不知道写什么了,博主变low了呀。springaop使得我们的aop开发工作变得简单,这是众所周知的今天还是带我的粉丝们一起揭秘springaop底层原理及实现吧哈哈哈哈AOP面向切面编程:主要是通过切面类来提高代码的复用,降低业务代码的耦合性,从而提高开发效率。主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理等等。AOP实现原理
Easter79 Easter79
3年前
Spring中的AOP(二)——AOP基本概念和Spring对AOP的支持
AOP的基本概念    AOP从运行的角度考虑程序的流程,提取业务处理过程的切面。AOP面向的是程序运行中的各个步骤,希望以更好的方式来组合业务逻辑的各个步骤。AOP框架并不与特定的代码耦合,AOP框架能处理程序执行中特定切入点,而不与具体某个类耦合(即在不污染某个类的情况下,处理这个类相关的切点)。下面是一些AOP的一些术语:    切面(
Easter79 Easter79
3年前
Spring框架中的AOP技术
1、AOP概述AOP技术即AspectOrientedProgramming的缩写,译为面向切面编程。AOP是OOP的一种延续,利用AOP技术可以对业务逻辑的各个部分进行隔离,从使得业务逻辑各部分之间的耦合性降低,提高程序的可重用性,同时提高了开发的效率。AOP采用横向抽取机制,取代了传统纵向继承体系重复性代码,AOP可以在不修改源代码的
Wesley13 Wesley13
3年前
Spring AOP教程
一、概念AOP(AspectOrientedProgramming):面向切面编程。面向切面编程(也叫面向方面编程),是目前软件开发中的一个热点,也是Spring框架中的一个重要内容。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。二、用途日志记
Stella981 Stella981
3年前
Redis应用学习——缓存的使用与设计
1\.缓存的收益与成本  1.收益:通过缓存加速读写速度。在内存中读写比硬盘速度快降低数据库服务器的负载。比如业务端的请求的数据大多数都由Redis服务器来处理,大大减轻MySQL服务器的压力  2.成本:数据不一致问题,比如Redis服务器与数据库服务器之间的某些数据可能会发
Wesley13 Wesley13
3年前
Spring学习总结(4)——Spring AOP教程
一、概念AOP(AspectOrientedProgramming):面向切面编程。面向切面编程(也叫面向方面编程),是目前软件开发中的一个热点,也是Spring框架中的一个重要内容。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。二、用途日志记
Wesley13 Wesley13
3年前
Java高级特性—反射和动态代理
1).反射  通过反射的方式可以获取class对象中的属性、方法、构造函数等,一下是实例:2).动态代理  使用场景:      在之前的代码调用阶段,我们用action调用service的方法实现业务即可。    由于之前在service中实现的业务可能不能够满足当先客户的要求,需要我们重新修改servic
服务端应用多级缓存架构方案 | 京东云技术团队
20w的QPS的场景下,服务端架构应如何设计?常规解决方案可使用分布式缓存来抗,比如redis集群,6主6从,主提供读写,从作为备,不提供读写服务。1台平均抗3w并发,还可以抗住,如果QPS达到100w,通过增加redis集群中的机器数量,可以扩展缓存的容量和并发读写能力。同时,缓存数据对于应用来讲都是共享的,主从架构,实现高可用。
基于javaPoet的缓存key优化实践
一.背景在一次系统opsreview中,发现了一些服务配置了@Cacheable注解。@cacheable来源于springcache框架中,作用是使用aop的方式将数据库中的热数据缓存在redis/本地缓存中,代码如下:@Cacheable(value"
RocksDB 二级缓存
RocksDB团队正在实现对非易失性介质上的块缓存的支持。可以看作是RocksDB当前的易失性块缓存的扩展。非易失性块缓存充当第二层缓存,其中包含从易失性缓存中逐出的块。当这些块由于访问而变得更热时,它们会被提升到易失性缓存中。
京东云开发者 京东云开发者
6个月前
基于javaPoet的缓存key优化实践
作者:京东物流方志民一.背景在一次系统opsreview中,发现了一些服务配置了@Cacheable注解。@cacheable来源于springcache框架中,作用是使用aop的方式将数据库中的热数据缓存在redis/本地缓存中,代码如下:@Cachea
史湘云
史湘云
Lv1
惊鸿一瞥而后不知所踪,这大概就是晚霞的美之所在。
文章
5
粉丝
0
获赞
0