【Spring4.0笔记整理十三】AOP五大通知

版权声明:本文为 小异常 原创文章,非商用自由转载-保持署名-注明出处,谢谢!
本文网址:https://blog.csdn.net/sun8112133/article/details/80551748

  通过上篇博客 HelloWorld(AOP篇),相信大家已经对 AOP编程 有了一个简单的认识,本篇将学习 AOP 中的五大通知。在 AOP详解 这篇博客中的 AOP术语 这一小节已经介绍过了什么是通知,通知用一句话概括就是切面类中的方法,每种通知都会在目标方法的不同位置执行。

AOP五大通知(Advice):

  一、前置通知(Before)

  二、后置通知(After)

  三、返回通知(AfterReturning)

  四、异常通知(AfterThrowing)

  五、环绕通知(Around)

【Spring4.0笔记整理十三】AOP五大通知_第1张图片

配置通知所需jar包:

  com.springsource.org.aopalliance-1.0.0.jar
  com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
  commons-logging-1.1.1.jar
  spring-aop-4.0.0.RELEASE.jar
  spring-beans-4.0.0.RELEASE.jar
  spring-context-4.0.0.RELEASE.jar
  spring-core-4.0.0.RELEASE.jar
  spring-expression-4.0.0.RELEASE.jar




一、四大通知

  前置通知(Before): 在目标方法开始前执行;
  后置通知(After): 在目标方法执行后执行(发生异常也会执行);
  返回通知(AfterReturning): 在目标方法正常结束后执行,能够获得该目标方法的返回值;
  异常通知(AfterThrowing): 在目标方法出现异常时执行,能够获得异常信息,也可以指定在出现特定异常时再执行此通知。

1、基于注解的方式

  1)HelloWorld类
@Component
public class HelloWorld {
    public int hello() {
        System.out.println("我是hello()方法!!!");
        return 1;
    }
}
  2)切面类
@Aspect
@Component
public class Time {
    @Before("execution(public int com.demo.HelloWorld.hello())")
    public void beforeTime(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();  // 目标方法名
        List list = Arrays.asList(joinPoint.getArgs());  // 目标方法的参数
        System.out.println("我是前置通知,我会在目标" + methodName + "方法前执行!!~");
    }
    @After("execution(public int com.demo.HelloWorld.hello())")
    public void afterTime(JoinPoint joinPoint) {
        System.out.println("我是后置通知,我会在目标方法最后执行,不管有没有发生异常,我都会被执行!!~");
    }
    @AfterReturning(value="execution(public int com.demo.HelloWorld.hello())", returning="result")
    public void returnTime(JoinPoint joinPoint, Object result) {
        // 注意这里的参数 result 的名字要和 注解中 returning 参数值一致
        System.out.println("目标方法的返回值是:" + result);
        System.out.println("我是返回通知,我会在目标方法正常结束后执行,如果发生了异常,我就不会被执行了!!~");
    }
    @AfterThrowing(value="execution(public int com.demo.HelloWorld.hello())", throwing="e")
    public void throwTime(JoinPoint joinPoint, Throwable e) {
        // 注意这里的参数 e 的名字要和 注解中 throwing 参数值一致
        System.out.println("目标方法的异常是:" + e);
        System.out.println("我是异常通知,我会在目标方法发生了异常时执行,如果不发生异常,我就不会被执行!!~");
    }
} 
  

注: JoinPoint 是切入点类,该类封装了目标方法(这里的目标方法也就是切入点)的信息,从这个类中可以获得目标方法的参数列表、方法名、以及所属类的Class等信息。

  3)配置XML

<context:component-scan base-package="com.demo" />

<aop:aspectj-autoproxy />
  4)测试类
// 1、创建 Spring 的 IOC 容器对象 
ApplicationContext ioc = new ClassPathXmlApplicationContext("bean.xml"); 
// 2、从 IOC 容器中获取 bean 实例 
HelloWorld helloWorld = (HelloWorld) ioc.getBean("helloWorld"); 
// 3、调用 hello方法
helloWorld.hello();

2、基于XML方式

  1)HelloWorld类
public class HelloWorld {
    public void hello() {
        System.out.println("我是hello()方法!!!");
    }
}
  2)切面类
public class Time {
    public void beforeTime(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();  // 目标方法名
        List list = Arrays.asList(joinPoint.getArgs());  // 目标方法的参数
        System.out.println("我是前置通知,我会在目标" + methodName + "方法前执行!!~");
    }
    public void afterTime(JoinPoint joinPoint) {
        System.out.println("我是后置通知,我会在目标方法最后执行,不管有没有发生异常,我都会被执行!!~");
    }
    public void returnTime(JoinPoint joinPoint, Object result) {
        // 注意这里的参数 result 的名字要和 注解中 returning 参数值一致
        System.out.println("目标方法的返回值是:" + result);
        System.out.println("我是返回通知,我会在目标方法正常结束后执行,如果发生了异常,我就不会被执行了!!~");
    }
    public void throwTime(JoinPoint joinPoint, Throwable e) {
        // 注意这里的参数 e 的名字要和 注解中 throwing 参数值一致
        System.out.println("目标方法的异常是:" + e);
        System.out.println("我是异常通知,我会在目标方法发生了异常时执行,如果不发生异常,我就不会被执行!!~");
    }
} 
  
  3)配置XML

<bean id="helloWorld" class="com.demo.HelloWorld">bean>

<bean id="time" class="com.demo.Time">bean>

<aop:config>
    
    <aop:aspect ref="time">
        <aop:before method="beforeTime" pointcut="execution(public int com.demo.HelloWorld.hello())" />
        <aop:after method="afterTime" pointcut="execution(public int com.demo.HelloWorld.hello())" />
        <aop:after-returning method="returnTime" returning="result" pointcut="execution(public int com.demo.HelloWorld.hello())" />
        <aop:after-throwing method="throwTime" throwing="e" pointcut="execution(public int com.demo.HelloWorld.hello())" />
    aop:aspect>
aop:config>
  4)测试类
// 1、创建 Spring 的 IOC 容器对象 
ApplicationContext ioc = new ClassPathXmlApplicationContext("bean.xml"); 
// 2、从 IOC 容器中获取 bean 实例 
HelloWorld helloWorld = (HelloWorld) ioc.getBean("helloWorld"); 
// 3、调用 hello方法
helloWorld.hello();

【Spring4.0笔记整理十三】AOP五大通知_第2张图片

  如果在目标方法中发生异常,比如 除0异常,会有以下效果:

【Spring4.0笔记整理十三】AOP五大通知_第3张图片

二、环绕通知

  环绕通知(Around): 围绕着目标方法执行,相当于是以上四大通知的集合。(一般很少使用)

1、基于注解的方式

  1)HelloWorld类
@Component
public class HelloWorld {
    public int hello() {
        System.out.println("我是hello()方法!!!");
        return 1;
    }
}
  2)切面类
@Aspect
@Component
public class Time {
    @Around("execution(public int com.demo.HelloWorld.hello())")
    public Object aroundTime(ProceedingJoinPoint pjd) {
        // 返回值
        Object result = null;
        // 方法名
        String methodName = pjd.getSignature().getName();
        // 参数列表 
        List list = Arrays.asList(pjd.getArgs());

        try {
            // 前置通知
            System.out.println("我是前置通知,我现在在环绕通知中。我会在目标方法之前执行!!");
            // 执行目标方法
            result = pjd.proceed();
            // 返回通知
            System.out.println("我是返回通知,我现在在环绕通知中。只有正常结束才执行,我还能获得返回值:" + result);
        } catch (Throwable e) {
            // 异常通知
            System.out.println("我是异常通知,我现在在环绕通知中。只有发生异常我才被执行,异常信息是:" + e);
        } finally {
            // 后置通知
            System.out.println("我是后置通知,我现在在环绕通知中。不管有没有异常,我都是最后被执行的!!其实环绕通知中的我也能获得返回值:" + result);
        }

        return result;
    }
} 
  
  3)配置XML

<context:component-scan base-package="com.demo" />

<aop:aspectj-autoproxy />
  4)测试类
// 1、创建 Spring 的 IOC 容器对象 
ApplicationContext ioc = new ClassPathXmlApplicationContext("bean.xml"); 
// 2、从 IOC 容器中获取 bean 实例 
HelloWorld helloWorld = (HelloWorld) ioc.getBean("helloWorld"); 
// 3、调用 hello方法
helloWorld.hello();

2、基于XML方式

  1)HelloWorld类
public class HelloWorld {
    public void hello() {
        System.out.println("我是hello()方法!!!");
    }
}
  2)切面类
public class Time {
    public Object aroundTime(ProceedingJoinPoint pjd) {
        // 返回值
        Object result = null;
        // 方法名
        String methodName = pjd.getSignature().getName();
        // 参数列表 
        List list = Arrays.asList(pjd.getArgs());

        try {
            // 前置通知
            System.out.println("我是前置通知,我现在在环绕通知中。我会在目标方法之前执行!!");
            // 执行目标方法
            result = pjd.proceed();
            // 返回通知
            System.out.println("我是返回通知,我现在在环绕通知中。只有正常结束才执行,我还能获得返回值:" + result);
        } catch (Throwable e) {
            // 异常通知
            System.out.println("我是异常通知,我现在在环绕通知中。只有发生异常我才被执行,异常信息是:" + e);
        } finally {
            // 后置通知
            System.out.println("我是后置通知,我现在在环绕通知中。不管有没有异常,我都是最后被执行的!!其实环绕通知中的我也能获得返回值:" + result);
        }

        return result;
    }
} 
  
  3)配置XML

<bean id="helloWorld" class="com.demo.HelloWorld">bean>

<bean id="time" class="com.demo.Time">bean>

<aop:config>
    
    <aop:aspect ref="time">
        <aop:around method="aroundTime" pointcut="execution(public int com.demo.HelloWorld.hello())" />
    aop:aspect>
aop:config>
  4)测试类
// 1、创建 Spring 的 IOC 容器对象 
ApplicationContext ioc = new ClassPathXmlApplicationContext("bean.xml"); 
// 2、从 IOC 容器中获取 bean 实例 
HelloWorld helloWorld = (HelloWorld) ioc.getBean("helloWorld"); 
// 3、调用 hello方法
helloWorld.hello();

【Spring4.0笔记整理十三】AOP五大通知_第4张图片

  如果在目标方法中发生异常,比如 除0异常,会有以下效果:

【Spring4.0笔记整理十三】AOP五大通知_第5张图片




你可能感兴趣的:(Spring)