简单了解AOP用法及理论,AOP缓存操作

AOP:
面向切面编程,通过预编译和运行时动态生成的代理类,对一类代码进行增强的操作
核心:
在不影响原有的代码的基础上,对方法进行扩展,减少代码的耦合性

切面 = 切入点表达式 + 通知

1.目标方法:
用户调用实际的业务代码
2.通知
:在切面中扩展目标方法的方法
3.切入点表达式:
相当于是一个if判断 当用户执行目标方法时,如果满足了切入点表达式,则执行通知方法
4.连接点:
当方法满足切入点表达式时,该方法称之为连接点

AOP切入点表达式
1.bean(bean的ID) 按照bean 的id匹配 某一个

2.within(包名.类名) 按类匹配 多个

上述2项都是粗粒度.

3.execution(返回值类型 包名.类名.方法名(参数列表))

方法参数级别: 粒度较细

4.@annotation(注解名称/注解的路径) 按照注解匹配.

通知总类
1).前置通知 在目标方法执行之前执行

2).后置通知 在目标方法执行之后执行

3).异常通知 在目标方法执行之后报异常的

4).最终通知 不管什么时候都要执行的通知

5).环绕通知 在目标方法前后都要执行的通知

总结:

1.前4大通知类型一般用于程序状态的记录.

2.环绕通知最为强大的通知方法,可以控制目标方法的执行.可以改变程序的流转的轨迹. 一般用于业务操作.

@Component      //将AOP 交给spring容器管理
@Aspect         //标识该类为AOP切面
public class TestAOP {
​
    //AOP   切面 = 切入点表达式 + 通知方法
    //1.bean  2.within   3.execution(返回值类型  包名.类名.方法名(参数列表))
    //@Pointcut("bean(itemCatServiceImpl)")
    //@Pointcut("within(com.jt.service.ItemCatServiceImpl)")
    @Pointcut("execution(* com.jt..*.*(..))")
    public void pointCut() {
        
    }
    
    //1.定义前置通知   获取参数数据
    @Before("pointCut()")
    public void before(JoinPoint joinPoint) {
        String className = 
                joinPoint.getSignature().getDeclaringTypeName();
        String methodName = joinPoint.getSignature().getName();
        Object[] objs = joinPoint.getArgs();    //获取目标方法的参数
        System.out.println(className);
        System.out.println(methodName);
        System.out.println(objs);
    }
}

AOP缓存操作
1.AOP缓存实现策略
1).自定义缓存注解 @Cache_Find 查询注解
2).自定义属性

@Target(ElementType.METHOD) //该注解对方法有效
@Retention(RetentionPolicy.RUNTIME) //运行期有效
public @interface CacheFind {
​
    //要求用户指定key的前缀,之后动态拼接key 
    public String perKey();
    //如果用户有超时时间则定义超时用法
    public int seconds() default 0;
}

实现缓存AOP

实现缓存AOP
@Aspect
@Component
public class CacheAOP {
    
    @Autowired
    private Jedis jedis;
    
    /**
     * 规定:ProceedingJoinPoint 参数必须位于第一位
     * 1.利用切入点表达式拦截@CacheFind注解,同时获取CacheFind注解对象
     * 2.自定义key
     * 3.根据key查询缓存.
     *      有数据:  则返回对象
     *      没有数据:  则查询数据库.之后将返回结果 保存到redis中
     * 
     * 
     * 反射相关:
     * 
     *  Method method = 
                joinPoint.getTarget()   //获取目标对象
                         .getClass()    //目标对象的class
                         .getMethod("findItemCatList", Long.class); //方法
                //从方法对象中获取返回值类型
                Class returnClass = method.getReturnType();
     * 
     *   
     */
    @SuppressWarnings("unchecked")
    //@Around("@annotation(com.jt.anno.CacheFind)")
    @Around("@annotation(cacheFind)")
    public Object  around(ProceedingJoinPoint joinPoint,CacheFind cacheFind) {
        
        Object result = null;
        try {
            Object[] args = joinPoint.getArgs();
            //动态拼接key
            String key = cacheFind.perKey()+"::"+Arrays.toString(args);
            //根据key查询redis
            if(!jedis.exists(key)) {
                //如果key不存在,则执行目标方法
                result = joinPoint.proceed();
                System.out.println("AOP查询数据库!!!!!!");
                //将返回值结果保存到redis中
                String json = ObjectMapperUtil.toJSON(result);
                int seconds = cacheFind.seconds();
                if(seconds>0)
                    //表示用户需要设定超时时间
                    jedis.setex(key, seconds, json);
                else 
                    //用户不需要超时时间
                    jedis.set(key, json);
            }else {
                //如果redis中有缓存,则将json串转化为对象之后返回
                String json = jedis.get(key);
                //如何才能动态的获取方法的返回值类型?????  必须获取方法对象
                MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();   //获取目标对象的方法
                result = 
                        ObjectMapperUtil.toObj(json,methodSignature.getReturnType());
                System.out.println("AOP缓存查询!!!!!!!");
            }
            
        } catch (Throwable e) {
            
            e.printStackTrace();
        }
        
        return result;
    }
}



你可能感兴趣的:(简单了解AOP用法及理论,AOP缓存操作)