AOP:xml和注解方式通知的执行顺序的区别

326 阅读2分钟

1.xml方式

部分通知执行先后顺序取决于配置的顺序


/**
 * 切面类
 */
public class MyAspect {
    //前置通知
    public void before(){
        System.out.println("before......");
    }
​
    //环绕通知   Proceeding  JoinPoint:正在执行的连接点-->切点
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("around-前....");
        Object result = joinPoint.proceed();
        System.out.println("around-后....");
        return result;
    }
    
    //后置通知
    //res接收目标对象方法返回值
    public void afterReturning(Object res){
        System.out.println("afterReturning.....");
        System.out.println("res:"+res);
    }
​
    //异常抛出通知
    public void afterThrowing(){
        System.out.println("afterThrowing....");
    }
​
    //最终通知
    public void after(){
        System.out.println("after.....");
    }
​
}
<!--配置织入:告诉Spring框架 哪些方法(切点)需要进行哪些增强/通知(前置、后置等等)-->
<aop:config>
    <!--声明切面-->
    <aop:aspect ref="myAspect">
        <!--切面:切点+通知-->
        <!--抽取切点-->
        <aop:pointcut id="pointcut" expression="execution(* com.itheima.aop.*.*(..))"/>
        
        <aop:before method="before" pointcut-ref="pointcut"/>
        <aop:around method="around" pointcut-ref="pointcut"/>
        <aop:after-returning method="afterReturning" pointcut-ref="pointcut" returning="res"/>
        <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut"/>
        <aop:after method="after" pointcut-ref="pointcut"/>
    </aop:aspect>
</aop:config>
/**
 * 目标对象
 */
public class Target implements TargetInterface {
    @Override
    public int save() {
        System.out.println("save running.....");
        // int i=1/0;
        return 10;
    }
}

1.1.可以看到,先配置前置通知before,再配置环绕通知around,正常情况下的执行顺序:

image.png

1.2.先配置环绕通知around,再配置前置通知before ,正常情况下的执行顺序:

image.png

1.3.异常情况:

@Override
public int save() {
    System.out.println("save running.....");
    int i=1/0;
    return 10;
}

image.png

1.4.总结:

1.前置通知before和环绕通知around的执行顺序取决于配置顺序, 后置通知afterReturning和最终通知after执行顺序取决于配置顺序

按上面的配置来看:

2.正常情况:before(或around-前)-->目标方法-->(around-后)-->afterReturning-->after

3.异常情况:before(或around-前)-->目标方法-->afterThrowing-->after

4.无论正常还是异常都会执行的通知:before、around-前、after;正常多一个afterReturning和around-后 ;异常多一个afterThrowing

2.注解方式

/**
 * 切面类
 */
@Component
@Aspect
public class MyAspect {
​
    //配置切点
    @Pointcut("execution(* com.itheima.anno.*.*(..))")
    public void pointcut(){}
​
    //环绕通知   Proceeding  JoinPoint:正在执行的连接点-->切点
    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("around-前....");
        Object result = joinPoint.proceed();
        System.out.println("around-后....");
        return result;
    }
​
    //前置通知
    @Before("pointcut()")
    public void before(){
        System.out.println("before......");
    }
​
    //后置通知
    //res接收目标对象方法返回值
    @AfterReturning(value = "pointcut()",returning = "res")
    public void afterReturning(Object res){
        System.out.println("afterReturning.....");
        System.out.println("res:"+res);
    }
​
    //异常抛出通知
    @AfterThrowing("pointcut()")
    public void afterThrowing(){
        System.out.println("afterThrowing....");
    }
​
    //最终通知
    @After("pointcut()")
    public void after(){
        System.out.println("after.....");
    }
​
}
/**
 * 目标对象
 */
@Component
public class Target implements TargetInterface {
    @Override
    public int save() {
        System.out.println("save running.....");
        // int i=1/0;
        return 10;
    }
}

2.1.注解方式环绕通知around比前置通知before先执行,与编写顺序无关,after通知比afterReturning先执行,正常如下:

image.png

2.2.异常情况:

image.png

2.3.总结:

1)正常情况:around-前-->before-->目标-->around-后-->after-->afterReturning

2)异常情况:around-前-->before-->目标-->after-->afterThrowing

3)正常或异常都执行的通知:around-前、before、after ;正常多一个afterReturning在最后和around-后;异常多一个afterThrowing在最后

3.两者区别

xml方式通知执行顺序受配置顺序影响,注解方式固定