在上文中,咱们尽管在业务层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);    }