(十)Spring AOP - 使用详解

(七)Spring AOP - 原理简介
(八)Spring AOP - 核心概念简介
(九)Spring AOP - 简单配置

1. 切点表达式

共分两类:

  • within表达式

    通过类名匹配,粗粒度切点表达式
    语法:within(包名.类名)

  • execution表达式(最常用)

    以方法为单位切入匹配,细粒度切点表达式
    语法:execution(返回值类型 包名.类名.方法名(参数类型,参数类型…))
    可以使用 &&, || 和 !等符号进行合并操作

    //&&:两个表达式同时
    execution( public int com.lazy.proxy.dynamic.Calculator.*(..)) && execution(* *.*(int,int) )
    //||:任意满足一个表达式即可
    execution( public int com.lazy.proxy.dynamic.Calculator.*(..)) && execution(* *.*(int,int) )
    //!:只要不是这个位置都可以进行切入
    //&&:两个表达式同时
    execution( public int com.lazy.proxy.dynamic.Calculator.*(..))
    

2. @Pointcut抽取切点

为之前写的计算器写个切面增强

@Pointcut("execution(* com.lazy.proxy.dynamic.Calculator.*(..) )")
public void point() {

}

@Before("point()")

3. 获取执行方法详细信息

@Component
@Aspect
public class CalculatorAspect {

    @Pointcut("execution(* com.lazy.proxy.dynamic.Calculator.*(..) )")
    public void point() {

    }

    @Before("point()")
    public void before(JoinPoint joinPoint) {
        System.out.println("****************方法执行前*****************");
        String methodName = joinPoint.getSignature().getName();
        System.out.println("---方法名:" + methodName);
        Object[] args = joinPoint.getArgs();
        System.out.println("---参数是:" + Arrays.asList(args));
    }

    @AfterReturning(value = "point()", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) {
        System.out.println("****************方法执行返回*****************");
        String methodName = joinPoint.getSignature().getName();
        System.out.println("---方法名:" + methodName);
        System.out.println("---方法执行完成,返回值是:" + result);
    }

    @AfterThrowing(value = "point()", throwing = "ex")
    public void afterThrowing(JoinPoint joinPoint, Exception ex) {
        System.out.println("****************方法执行异常*****************");
        String methodName = joinPoint.getSignature().getName();
        System.out.println("---方法名:" + methodName);
        System.out.println("---方法执行异常,异常是:" + ex.getMessage());
    }

    @After(value = "point()")
    public void after(JoinPoint joinPoint) {
        System.out.println("****************方法执行完成*****************");
        String methodName = joinPoint.getSignature().getName();
        System.out.println("---方法名:" + methodName);
    }
}

4. 通知方法的执行顺序

正常执行:@Before—>@AfterReturning—>@After

@Test
public void testAfterReturning() {
    ICalculator calculator = context.getBean(ICalculator.class);
    int sum = calculator.sum(3, 5);
    System.out.println("---sum结果:" + sum);
}

Test:
在这里插入图片描述

异常执行:@Before—>@AfterThrowing—>@After

@Override
public int sub(int numA, int numB) throws Exception {
    if (numA < 0) {
        throw new Exception("不能小于0");
    }
    int result = numA - numB;
    return result;
}


@Test
public void testAfterThrowing() {
    ICalculator calculator = context.getBean(ICalculator.class);
    int sum = 0;
    try {
        sum = calculator.sub(-1, 5);
    } catch (Exception e) {
        //e.printStackTrace();
    }
    System.out.println("---sum结果:" + sum);
}

Test:
在这里插入图片描述

5. 环绕通知,最强大的通知,需要自己调用执行方法

/**
* @Description: 环绕通知
*/
@Around(value = "point()")
public Object around(ProceedingJoinPoint joinPoint) {
    String methodName = joinPoint.getSignature().getName();
    Object[] args = joinPoint.getArgs();
    Object proceed = null;
    try {
        System.out.println("##########  方法环绕前置通知,方法名:" + methodName + " #####  参数:" + Arrays.asList(args));
        //利用反射调用目标方法,就是method.invoke()
        proceed = joinPoint.proceed(args);
        System.out.println("##########  方法环绕后置返回通知,返回值:" + proceed );
    } catch (Throwable throwable) {
        System.out.println("##########  方法环绕后置异常通知,返回值:" + throwable.getMessage() );
    } finally {
        System.out.println("##########  方法环绕后置通知,方法名:" + methodName );
    }
    return proceed;
}

Test:
在这里插入图片描述

环绕通知方法有返回值,不写返回值可能会抛出异常

org.springframework.aop.AopInvocationException: Null return value from advice does not match primitive return type for

6. xml配置

<bean id="calculatorAspect" class="com.lazy.aspect.CalculatorAspect"></bean>
<aop:config>
    <aop:pointcut id="globalPoint" expression="execution(* com.lazy.proxy.dynamic..*(..))"/>
    <aop:aspect ref="calculatorAspect">
        <aop:pointcut id="mypoint" expression="execution(* com.lazy.proxy.dynamic..*(..))"/>
        <aop:before method="before" pointcut-ref="mypoint"></aop:before>
        <aop:after method="after" pointcut-ref="mypoint"></aop:after>
        <aop:after-returning method="afterReturning" pointcut-ref="mypoint" returning="result"></aop:after-returning>
        <aop:after-throwing method="afterThrowing" pointcut-ref="mypoint" throwing="ex"></aop:after-throwing>
        <aop:around method="around" pointcut-ref="mypoint"></aop:around>
    </aop:aspect>
</aop:config>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值