Spring Boot 学习之路——4.1 AOP注解方式实现打印日志 详解

以下内容转自:https://www.cnblogs.com/lixiang1993/p/7447853.html


1.声明一个切面类,并把这个切面类加入到IOC容器中

@Component
@Aspect
public class LogAspect{
    @Pointcut(value="execution(* *.*(..))")
    public void showLog(){}
    @Before(value="showLog()")
    public void showBeginLog(){
        System.out.println("AOP日志开始");
    }
    @After(value="showLog()")
    public void showReturnLog(){
        System.out.println("AOP方法结束");
    }
    @AfterThrowing(value="showLog()")
    public void showExceptionLog(){
        System.out.println("AOP方法异常");
    }
    @AfterReturning(value="showLog()")
    public void showAfterLog(){
        System.out.println("AOP方法最终返回");
    }
}

2.被代理的对象也需要加入IOC容器

@Component
public class MathCalculator {
    public void add(int i, int j) {
        int result=i+j;
        System.out.println("目标方法add(int)执行了");
    }
    public void sub(int i, int j) {
        int result=i-j;
        System.out.println("目标方法sub执行了");
    }
    public void mult(int i, int j) {
        int result=i*j;
        System.out.println("目标方法mult执行了");
    }
    public void div(int i, int j) {
        int result=i/j;
        System.out.println("目标方法div执行了");
    }
}

3.切入点表达式

  • 切入点表达式的语法格式

execution([权限修饰符] [返回值类型] [简单类名/全类名] [方法名]([参数列表]))

  • 切入点表达式支持通配符
  • 两种切入表达式
    • 最详细的切入点表达式:

 

execution(public void com.bwlu.aop.MathCalculator.add(int, int))

 

    • 最模糊的切入点表达式:
execution (* *.*(..))

execution(public void com.bwlu.aop.MathCalculator.add(int, int)):只有add方法加入了4个通知,

execution(public void com.bwlu.aop.MathCalculator.*(int, int)):任意方法,参数为int,int

execution(public void com.bwlu.aop.MathCalculator.*(..)):MathCalculator中的任意方法,任意参数列表

execution(public * com.bwlu.aop.MathCalculator.*(..)):MathCalculator中的任意方法,任意参数列表,任意返回值

execution( * com.bwlu.aop.MathCalculator.*(..)):MathCalculator中的任意方法,任意参数列表,任意返回值,任意访问修饰符

execution (* *.*(..)):任意匹配

需要注意的是:权限是不支持写通配符的,当然你可以写一个*表示所有权限所有返回值!


4.通知方法的细节

(1)在通知中获取目标方法的方法名和参数列表

  • 在通知方法中声明一个JoinPoint类型的形参
  • 调用JoinPoint对象的getSignature()方法获取目标方法的签名
  • 调用JoinPoint对象的getArgs()方法获取目标方法的实际参数列表

(2)在返回通知中获取方法的返回值

  • 在@AfterReturning注解中添加returning属性:@AfterReturning (value="showLog()", returning= "result")
  • 在返回通知的通知方法中声明一个形参,形参名和returning属性的值一致:showReturnLog(JoinPoint joinPoint, Object result)

(3)在异常通知中获取异常对象

  • 在@ AfterThrowing注解中添加throwing属性:@AfterThrowing (value="showLog()",throwing= "throwable" )
  • 在异常通知的通知方法中声明一个形参,形参名和throwing属性值一致:showExceptinLog(JoinPoint joinPoint, Throwable throwable)
@Component
@Aspect
public class LogAspect{
    @Pointcut(value="execution(* *.*(..))")
    public void showLog(){}
    @Before(value="showLog()")
    public void showBeginLog(JoinPoint jPoint){
        Object[] args = jPoint.getArgs();
        List<Object> asList = Arrays.asList(args);
        Signature signature = jPoint.getSignature();
        String name = signature.getName();
        System.out.println("AOP日志开始");
        System.out.println("目标方法名:"+name+",参数列表:"+asList);
    }
    @After(value="showLog()")
    public void showReturnLog(){
        System.out.println("AOP方法结束");
    }
    @AfterThrowing(value="showLog()",throwing="ex")
    public void showExceptionLog(Exception ex){
        System.out.println("AOP方法异常");
        System.out.println("异常信息:"+ex.getMessage());
    }
    @AfterReturning(value="showLog()",returning="result")
    public void showAfterLog(Object result){
        System.out.println("方法返回值:"+result);
        System.out.println("AOP方法最终返回");
    }
}


5.环绕通知@Around

环绕通知需要在方法的参数中指定JoinPoint的子接口类型ProceedingJoinPoint为参数:

public void around(ProceedingJoinPoint joinPoint){}

环绕通知能够替代其他4个通知。
注意:@Around修饰的方法一定要将方法的返回值返回!本身相当于代理!

@Component
@Aspect
public class LogAspect{
    @Around(value="execution(* *.*(..))")
    public Object showLog(ProceedingJoinPoint point){
        Object[] args = point.getArgs();
        List<Object> asList = Arrays.asList(args);
        Signature signature = point.getSignature();
        String name = signature.getName();
        Object result = null;
        try {
            try {
                //目标方法之前要执行的操作,相当于@before
                System.out.println("[环绕日志]"+name+"开始了,参数为:"+asList);
                //调用目标方法
                result = point.proceed(args);
            } finally {
                //方法最终结束时执行的操作,相当于@after
                System.out.println("[环绕日志]"+name+"结束了!");
            }
            //目标方法正常执行之后的操作,相当于@AfterReturning
            System.out.println("[环绕日志]"+name+"返回了,返回值为:"+result);
        } catch (Throwable e) {
            //目标方法抛出异常信息之后的操作,相当于@AfterThrowing
            System.out.println("[环绕日志]"+name+"出异常了,异常对象为:"+e);
            throw new RuntimeException(e.getMessage());
        }
        return result;
    }
}


6、切面的优先级

对于同一个代理对象,可以同时有多个切面共同对它进行代理。
可以在切面类上通过@Order (value=50)注解来进行设置,值越小优先级越高!

@Aspect

@Component

@Order(value=40)

public class LogAspect {}




明天再加日志配置说明,洗洗睡了先



















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值