Spring Aop的简单记录

1、Aop:面向切面编程

项目可以粗略划分为两个模块:核心业务、周边功能。所谓切面,就是将周边功能抽离出来,做相应的处理的一种定义。

切面可以带来的好处是,减少了重复的代码,将核心业务与周边功能解耦。

2、Aop的一些定义

  • 连接点:程序执行的具体操作,例如:执行一个方法
  • 切入点(Pointcut):在哪些类,哪些方法上切入,一般是一组连接点匹配表达式
  • 通知(Advice):在方法执行的时间段(around、before、after、exception、return)做一些增强的功能
  • 切面(Aspect):切面 = 切入点 + 通知,通俗点就是:在什么时机,什么地方,做什么增强!
  • 织入(Weaving):把切面加入到对象,并创建出代理对象的过程。(由 Spring 来完成)
  • Aop代理(aop proxy) : aop框架创建的对象,有两种jdk动态代理、CGLIB代理。

3、Aop织入的时期

编译期:切面在目标类编译时织入,AspectJ就是这种方式
类加载期:切面在目标类加载到JVM时织入
运行期:切面在程序运行的某个时期被织入,一般在切面织入时:AOP容器会对目标对象动态创建一个代理对象。Spring Aop就是采用这种织入方式。

4、Aop的一些注解

@Ascept,定义切面类
@Pointcut("execution(* com.example.springboot.controller.UserController.getVerify(..))"),标注切面的点
Advice的几个分类:
@Before 前置通知,在连接点方法前调用
@Around 环绕通知,它将覆盖原有方法,但是允许你通过反射调用原有方法,
@After 后置通知,在连接点方法后调用
@AfterReturning 返回通知,在连接点方法执行并正常返回后调用,要求连接点方法在执行过程中没有发生异常
@AfterThrowing 异常通知,当连接点方法异常时调用

5、Aop+注解+Redis实现Controller层简单的缓存读取

缺陷的地方:缓存数据与db一致性、缓存读取数据类型转换出错、缓存键id问题

定义注解:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CacheTarget {

    /**
     * 默认键
     * @return
     */
    String key() default "-1";

    /**
     * 转换的对象类型
     * @return
     */
    Class type() default Object.class;
}

定义Aop:

@Slf4j
@Component
@Aspect
public class CacheAop {

    @Autowired
    private RedisUtil redisUtil;

    @Pointcut("@annotation(com.example.springboot.annotation.CacheTarget)")
    public void point(){}

    @Around(value = "point()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("==around==");

        //得到其方法签名
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();

        CacheTarget cacheTarget = methodSignature.getMethod().getAnnotation(CacheTarget.class);

        String key = cacheTarget.key();

        //后续可以做缓存中数据类型相关操作
        Class type = cacheTarget.type();

        //参数名
        String[] parameterNames = methodSignature.getParameterNames();
        //参数值
        Object[] args = joinPoint.getArgs();

        //获取id的值
        int index = ArrayUtils.indexOf(parameterNames,"id");
        int id = (int)args[index];

        Object cacheValue = redisUtil.get(key + id);
        if(cacheValue != null){
            return cacheValue;
        }

        System.out.println("执行proceed");
        //执行方法
        Object result = joinPoint.proceed(args);

        return result;
    }

}

方法上使用该注解:

    /**
     * 根据id获取用户 + 缓存处理
     * @param id
     * @return
     */
    @CacheTarget(key = "user:", type = User.class)
    @GetMapping(value = "/redis/{id}")
    public User getUser(@PathVariable int id){
        log.info("执行mapper查询db");
        User user = userMapper.selectById(id);
        String cacheKey = USER_KEY + id;
        redisUtil.setEx(cacheKey,user,100);
        return user;
    }
关于学习到的一些记录与知识总结
原文地址:https://www.cnblogs.com/Zxq-zn/p/14320150.html