Spring-AOP学习笔记-03通知

Posted Moon&&Dragon

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring-AOP学习笔记-03通知相关的知识,希望对你有一定的参考价值。

5 通知的类型和使用

5.1 Before

前置通知,该通知是在连接点之前实现的,增强了连接点的前置方法,在前置方法中,我们可以拿到这个连接点,但是不可以对原来连接点方法的执行进行组织。

书写一个切面类,里面书写一个前置方法,在这个方法中我们拿到连接点

public class MyAspect {
 		// 前置方法
    public void before(JoinPoint joinPoint) throws Throwable {
        System.out.println("前置方法执行了,准备执行"+joinPoint.getSignature());
    }
}

配置配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--需要被代理的类-->
    <bean id="Man" class="com.moon.point.Man"/>
    <!--切面类-->
    <bean id="aspect" class="com.moon.aspect.MyAspect"/>
    <!--配置aop-->
    <aop:config>
     
        <!--配置aop切点-->
        <aop:pointcut id="point" expression="execution(public * com.moon..Man.*(..))"/>

        <!--配置切面切入-->
        <aop:aspect ref="aspect">
          <!--配置前置通知,切面的方法    切点-->
          <aop:before method="before" pointcut-ref="point" />
        </aop:aspect>
    </aop:config>
</beans>

结果:

在这里插入图片描述

5.2 After Advice

after后置方法是分为三类,主要是针对方法执行后三种状态,分别可以获得结果,捕获异常,finally执行。

在AfterAdvice中,同样也可以获得连接点JoinPoint

5.2.1 After-finally

我们使用的afterAdvice其实就是After-finally,是放在finally块中,不管方法执行结果是什么,都会执行

在After-finally中,同样也可以获得连接点JoinPoint

切面:

public class MyAspect {
 		// 前置方法
    public void before(JoinPoint joinPoint) throws Throwable {
        System.out.println("前置方法执行了,准备执行"+joinPoint.getSignature());
    }
  
  	// 后置方法
 	  public void after(JoinPoint joinPoint) throws Throwable {
        System.out.println("后置方法执行了,执行完了"+joinPoint.getSignature());
    }
}

XML配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--需要被代理的类-->
    <bean id="Man" class="com.moon.point.Man"/>
    <!--切面类-->
    <bean id="aspect" class="com.moon.aspect.MyAspect"/>
    <!--配置aop-->
    <aop:config>
     
        <!--配置aop切点-->
        <aop:pointcut id="point" expression="execution(public * com.moon..Man.*(..))"/>

        <!--配置切面切入-->
        <aop:aspect ref="aspect">
          <!--配置前置通知,切面的方法    切点-->
          <aop:before method="before" pointcut-ref="point" />
          <!--配置后置通知,切面方法     切点-->
          <aop:after method="after" pointcut-ref="point" />
        </aop:aspect>
    </aop:config>
</beans>

结果:

在这里插入图片描述

5.2.2 After-returning

AfterReturning是放在连接点执行后面,可以获得连接点执行完返回的值,同样也可以拿到连接点JoinPoint

这里我们直接拿返回的值,就不拿连接点

切面:

public class MyAspect {
 		// 前置方法
    public void before(JoinPoint joinPoint) throws Throwable {
        System.out.println("前置方法执行了,准备执行"+joinPoint.getSignature());
    }
  
  	// 后置返回方法
 	  public void afterReturning(Object result){
        System.out.println("后置返回方法执行");
        System.out.println("返回值为:"+result);
    }
}

XML:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--需要被代理的类-->
    <bean id="Man" class="com.moon.point.Man"/>
    <!--切面类-->
    <bean id="aspect" class="com.moon.aspect.MyAspect"/>
    <!--配置aop-->
    <aop:config>
     
        <!--配置aop切点-->
        <aop:pointcut id="point" expression="execution(public * com.moon..Man.*(..))"/>

        <!--配置切面切入-->
        <aop:aspect ref="aspect">
          <!--配置前置通知,切面的方法    切点-->
          <aop:before method="before" pointcut-ref="point" />
          <!--配置后置返回通知,切面方法
												   	 切点
													   返回值接收对象-->
          <aop:after-returning method="afterReturning" 
                               pointcut-ref="point" 
                               returning="result"/>
        </aop:aspect>
    </aop:config>
</beans>

结果:

这里的eat方法没有设置返回值,所以返回值为null

在这里插入图片描述

5.2.3 After-throwing

后置异常通知,顾名思义,就是在连接点方法发生异常的时候,才会执行,其实这个通知是放在catch块里面的,用来捕获异常。

注意:

  • 异常通知和返回结果通知是互斥的,俩者只有一个会被执行,如果出现异常就拿不到返回值,拿到返回值就说明没有异常。
  • 正常的后置通知,是放在finally块中,所以一定会被执行。

切面:

public class MyAspect {
 		// 前置方法
    public void before(JoinPoint joinPoint) throws Throwable {
        System.out.println("前置方法执行了,准备执行"+joinPoint.getSignature());
    }
  
  	// 后置异常方法
 	  public void afterThrowing(Exception e){
        System.out.println("后置异常方法执行");
        System.out.println("异常信息为:"+e.getMessage());
    }
}

XML:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--需要被代理的类-->
    <bean id="Man" class="com.moon.point.Man"/>
    <!--切面类-->
    <bean id="aspect" class="com.moon.aspect.MyAspect"/>
    <!--配置aop-->
    <aop:config>
     
        <!--配置aop切点-->
        <aop:pointcut id="point" expression="execution(public * com.moon..Man.*(..))"/>

        <!--配置切面切入-->
        <aop:aspect ref="aspect">
          <!--配置前置通知,切面的方法    切点-->
          <aop:before method="before" pointcut-ref="point" />
          <!--配置后置返回通知,切面方法
												   	 切点
													   异常接收对象-->
          <aop:after-throwing method="afterThrowing" 
                              pointcut-ref="point" 
                              throwing="e"/>
        </aop:aspect>
    </aop:config>
</beans>

这里对man类,代理的目标类进行修改,抛一个异常

public class Man implements Person{
    @Override
    public void eat() {
        System.out.println("吃饭");
        throw new RuntimeException("它没异常,我制造异常,哎,就是玩");
    }
}

结果:

在这里插入图片描述

5.3 Around Advice

AroundAdvice,环绕通知,该通知的特点是可以自定义代理,很类似一个代理类,把连接点方法直接给我们,我们可以选择执行或者不执行,默认是不执行的,这里我们拿的连接点就需要是ProceedingJoinPoint,该连接点仅支持环绕通知。

切面:

public class MyAspect {
  	// 环绕通知方法
 		public Object around(ProceedingJoinPoint joinPoint)throws Throwable{
        try {
            System.out.println("前置通知");
            // 通过proceed控制目标方法的执行
            Object proceed = joinPoint.proceed();
            //返回值后置通知
            System.out.println("返回值是"+proceed+",返回值后置通知");
            return proceed;
        } catch (Throwable throwable) {
            System.out.println("异常通知:异常信息为:"+throwable.getMessage());
            // 为了避免事务失效,所以要将异常跑出去ΩΩ
            throw  throwable;
        } finally {
            System.out.println("后置通知");
            System.out.println("============");
        }
    }
}

XML:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--需要被代理的类-->
    <bean id="Man" class="com.moon.point.Man"/>
    <!--切面类-->
    <bean id="aspect" class="com.moon.aspect.MyAspect"/>
    <!--配置aop-->
    <aop:config>
     
        <!--配置aop切点-->
        <aop:pointcut id="point" expression="execution(public * com.moon..Man.*(..))"/>

        <!--配置切面切入-->
        <aop:aspect ref="aspect">
          <!--配置环绕通知-->
          <aop:around method="around" pointcut-ref="point"/>
        </aop:aspect>
    </aop:config>
</beans>

结果:

在这里插入图片描述

5.4 执行顺序

在这里插入图片描述

以上是关于Spring-AOP学习笔记-03通知的主要内容,如果未能解决你的问题,请参考以下文章

Spring-AOP学习笔记-04 注解配置

Spring-AOP学习笔记-01 初识AOP

Spring-AOP学习笔记-02 连接点

Spring-AOP的5种通知

spring-aop-2

spring-AOP之通知和顾问