spring的AOP@EnableAspectJAutoProxy

个人博客地址: http://www.chenguanting.top

文章目录

  • 引子:
  • 方案
  • 实现步骤
  • 详细解释

引子:

有一个包中的所有方法都需要打印出方法的执行时间,并打印出参数和返回值。

方案

如果我们在每一个方法上都加上一套计算时间的逻辑,将会消耗大量的重复工作,并且等不需要用的时候有需要一个一个删除,这是很恶心人的事情。这时不妨试用下spring的aop

实现步骤

  1. 引入依赖
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-aopartifactId>
        dependency>
  1. 在启动类加上@EnableAspectJAutoProxy注解
@SpringBootApplication
@EnableAspectJAutoProxy
public class NoteApplication {
    public static void main(String[] args) {
        SpringApplication.run(NoteApplication.class, args);
    }
}
  1. 创建一个需要被添加日志的类,以下以controller为例
package com.yuyu.learning.note.controller;

@RestController()
@RequestMapping("/testRest" )
public class TestRest {
    @GetMapping("/test")
    public String test(@RequestParam("name") String name) {
        System.out.println("test:" + name);
        return "result:" + name;
    }
}
  1. 创建AOP类
package com.yuyu.learning.note.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.lang.reflect.Modifier;

@Aspect
@Component
public class AopLog {

    @Pointcut(value = "execution(* com.yuyu.learning.note.controller.TestRest.test(..)) && args(name)")
    public void point(String name) {
    }

    /**
     * 方法执行前
     *
     * @param joinPoint
     * @param name      参数
     */
    @Before(value = "point(name)")
    public void beforeMethod(JoinPoint joinPoint, String name) {
        System.out.println("目标方法名为:" + joinPoint.getSignature().getName());
        System.out.println("目标方法所属类的简单类名:" + joinPoint.getSignature().getDeclaringType().getSimpleName());
        System.out.println("目标方法所属类的类名:" + joinPoint.getSignature().getDeclaringTypeName());
        System.out.println("目标方法声明类型:" + Modifier.toString(joinPoint.getSignature().getModifiers()));
        //获取传入目标方法的参数
        Object[] args = joinPoint.getArgs();
        for (int i = 0; i < args.length; i++) {
            System.out.println("第" + (i + 1) + "个参数为:" + args[i]);
        }
        System.out.println("被代理的对象:" + joinPoint.getTarget());
        System.out.println("代理对象自己:" + joinPoint.getThis());

        System.out.println("beforeMethod\t" + name);
    }


    /**
     * 方法执行后
     *
     * @param joinPoint
     * @param name      参数
     */
    @After("point(name)")
    public void afterMethod(JoinPoint joinPoint, String name) {
        System.out.println("调用了后置通知\t" + name);
    }

    /**
     * 返回通知
     *
     * @param joinPoint
     * @param result    返回内容
     * @param name      传入参数
     */
    @AfterReturning(value = "point(name)", returning = "result")
    public void afterReturningMethod(JoinPoint joinPoint, Object result, String name) {
        System.out.println("调用了返回通知\t" + result);

    }

    /**
     * 异常通知
     *
     * @param joinPoint
     * @param e
     * @param name
     */
    @AfterThrowing(value = "point(name)", throwing = "e")
    public void afterReturningMethod(JoinPoint joinPoint, Exception e, String name) {
        System.out.println("调用了异常通知");
    }

    /**
     * 环绕通知
     *
     * @param pjp
     * @param name
     * @return
     * @throws Throwable
     */
    @Around("point(name)")
    public Object Around(ProceedingJoinPoint pjp, String name) throws Throwable {
        System.out.println("around执行方法之前");
//        Object object = pjp.proceed();
        Object object = pjp.proceed(new Object[]{"新参数"});
        System.out.println("around执行方法之后--返回值" + object);
        return object;
    }
}

详细解释

  1. @Aspect 声明这个类是切面类
  2. @Component 声明为组件,将类交给spring管理
  3. @Pointcut 声明切点
    3.1 execution(* com.yuyu.learning.note.controller.TestRest.test(…)) 这个是声明方法的位置,可以使用正则表达式,我这里精确匹配到了这个test方法
    3.2 args(name) 制定参数为name,如果有两个参数就是args(name1,name2);这时下面方法的参数需要个数/参数名称匹配才可以
    spring的AOP@EnableAspectJAutoProxy_第1张图片
  4. value = “point(name)” point(arg)指向了定义切点的方法,里面的参数必须和本方法中的参数一致
    spring的AOP@EnableAspectJAutoProxy_第2张图片
  5. @Around(“point(name)”) 特别说下around通知,在这个位置是可以修改传入方法的参数值的
@Around("point(name)")
    public Object Around(ProceedingJoinPoint pjp, String name) throws Throwable {
        System.out.println("around执行方法之前");
        Object object = pjp.proceed(new Object[]{"新参数"});
        System.out.println("around执行方法之后--返回值" + object);
        return object;
    }
    // 这个位置调用了可以传入参数数组的方法
	public Object proceed(Object[] args) throws Throwable;

你可能感兴趣的:(spring)