AspectJ支持5种类型的通知注解:

  • @Before:前置通知,在方法执行之前执行;
  • @After:后置通知,在方法执行之后执行;
  • @AfterRunning:返回通知,在方法返回结果之后执行(因此该通知方法在方法抛出异常时,不能执行);
  • @AfterThrowing:异常通知,在方法抛出异常之后执行;
  • @Around:环绕通知,围绕着方法执行。

示例项目新建:

第一步:新建spring aop项目

第二步:添加spring-aop.xml Spring配置文件:

<?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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<!-- 配置自动扫描的包 -->
<context:component-scan base-package="com.dx.spring.beans.aop"></context:component-scan>
<!-- 配置是AspectJ注解起作用 :自动为匹配的类生成代理对象 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

第三步:添加接口类IArithmeticCalculator.java,ArithmeticCalculatorImpl.java Spring组件

package com.dx.spring.beans.aop;

/**
* Description:Addition, subtraction, multiplication, and division
*/
public interface IArithmeticCalculator {
int add(int i, int j); int sub(int i, int j); int multi(int i, int j); int div(int i, int j);
}
package com.dx.spring.beans.aop;

import org.springframework.stereotype.Component;

@Component("arithmeticCalculator")
public class ArithmeticCalculatorImpl implements IArithmeticCalculator {
@Override
public int add(int i, int j) {
int result = i + j;
return result;
} @Override
public int sub(int i, int j) {
int result = i - j;
return result;
} @Override
public int multi(int i, int j) {
int result = i * j;
return result;
} @Override
public int div(int i, int j) {
int result = i / j;
return result;
}
}

第四步:添加LoggingAspect.java切面

package com.dx.spring.beans.aop;

import java.util.List;
import java.util.Arrays; import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component; //把这个类声明为一个切面:需要把该类放入到IOC容器中、再声明为一个切面。
@Aspect
@Component
public class LoggingAspect {
// 在这里注册通知方法。
}

第五步:添加测试类Client.java

package com.dx.spring.beans.aop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class Client {
public static void main(String[] args) {
// 1:创建Spring的IOC容器;
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-aop.xml");
// 2.从IOC容器中获取Bean的实例
IArithmeticCalculator arithmeticCalculator = (IArithmeticCalculator) ctx.getBean("arithmeticCalculator");
// 3.使用Bean }
}

@Before:前置通知

在切面类LoggingAspect中添加前置通知:

    // 声明该方法为一个前置通知:在目标方法开始之前执行
@Before("execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(int, int))")
public void beforeMethod(JoinPoint joinpoint) {
String methodName = joinpoint.getSignature().getName();
List<Object> args = Arrays.asList(joinpoint.getArgs());
System.out.println("before method " + methodName + " with " + args);
}

Client.java添加测试代码&执行测试:

        int result = arithmeticCalculator.add(1, 3);
System.out.println(result); result = arithmeticCalculator.div(4, 1);
System.out.println(result);

before method add with [1, 3]
before method div with [4, 0]

@After:后置通知

在切面类LoggingAspect中添加后置通知方法:

    // 声明该方法为一个后置通知:在目标方法结束之后执行(无论方法是否抛出异常)。
// 但是因为当方法抛出异常时,不能返回值为null,因此这里无法获取到异常值。
@After(value = "execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(int, int))")
public void afterMethod(JoinPoint joinpoint) {
String methodName = joinpoint.getSignature().getName();
List<Object> args = Arrays.asList(joinpoint.getArgs());
System.out.println("after method " + methodName);
}

Client.java添加测试代码&执行测试:

        int result = arithmeticCalculator.add(1, 3);
System.out.println(result); result = arithmeticCalculator.div(4, 0);
System.out.println(result);

执行结果:

备注:从执行结果中我们可以看出,即使方法抛出异常,后置通知方法也会执行。

@AfterRunning:返回通知

修改切面类LoggingAspect,添加返回通知方法:

    /**
* 声明该方法为一个返回通知:在目标方法返回结果时后执行(当方法抛出异常时,无法执行)。
* 但是因为当方法抛出异常时,类似代码
* {@code
* try <br/>
* { <br/>
* // before 前置通知 <br/>
* // do action method <br/>
* // after returning 返回通知,可以访问到方法的返回值 <br/>
* }
* catch(Exception e){
* e.printStackTrace();
* // after throwing 异常通知,可以访问到方法出现的异常
* }
* // after 后置通知,因为方法可以抛出异常,所以访问不到方法的返回值
* }
* */
@AfterReturning(value = "execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(int, int))",
returning = "result")
public void afterReturningMethod(JoinPoint joinpoint, Object result) {
String methodName = joinpoint.getSignature().getName();
List<Object> args = Arrays.asList(joinpoint.getArgs());
System.out.println(
"after method " + methodName + " with returning " + (result == null ? "NULL" : result.toString()));
}

注意:返回通知注解中,参数是多一个了returning参数,该参数定义通知方法接收返回值的别名。

在测试类Client.java中追加测试代码:

        int result = arithmeticCalculator.add(1, 3);
System.out.println(result); result = arithmeticCalculator.div(4, 0);
System.out.println(result);

@AfterThrowing:异常通知

修改切面类LoggingAspect,添加异常通知方法:

    /**
* 定义一个异常通知函数:
* 只有在方法抛出异常时,该方法才会执行,而且可以接受异常对象。
* */
@AfterThrowing(value = "execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(int, int))", throwing = "ex")
public void afterThrowingMethod(JoinPoint joinpoint, Exception ex) {
String methodName = joinpoint.getSignature().getName();
List<Object> args = Arrays.asList(joinpoint.getArgs());
System.out.println(
"after method " + methodName + " occurs exception: " + (ex == null ? "NULL" : ex.getMessage()));
}

备注:只有在方法抛出异常时,异常通知方法才会执行,而且可以接受异常对象。

在测试类Client.java中追加测试代码:

        int result = arithmeticCalculator.add(1, 3);
System.out.println(result); result = arithmeticCalculator.div(4, 0);
System.out.println(result);

打印信息

@Around:环绕通知

环绕通知其他方式不同,它相当于代理对象使用时效果一样。可以在方法前、后、返回、异常打印信息。

我们先看代理方法打印信息时如何处理,之后再看环绕通知如何处理。

代理方法实现通知:

package com.dx.spring.beans.aop;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; public class ArithmeticCalculatorProxy implements InvocationHandler {
private Object obj; public ArithmeticCalculatorProxy(Object obj) {
this.obj = obj;
} public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object object = null;
try {
// *** 前置通知,在方法执行之前执行
System.out.println("before " + method); // 真实的调用方法操作
object = method.invoke(obj, args); // *** 返回通知,在方法返回结果之后执行(因此该通知方法在方法抛出异常时,不能执行);
System.out.println("before returning " + method);
} catch (Exception ex) {
ex.printStackTrace();
// *** 异常通知,在方法抛出异常之后执行;
System.out.println("before throwing " + method);
throw ex;
}
// *** 后置通知,在方法执行之后执行;因为方法可以抛出异常,所以访问不到方法的返回值
System.out.println("after " + method); return object;
}
}

环绕通知:

修改切面类LoggingAspect,添加环绕通知:

package com.dx.spring.beans.aop;

import java.util.List;
import java.util.Arrays; import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component; //把这个类声明为一个切面:需要把该类放入到IOC容器中、再声明为一个切面。
@Aspect
@Component
public class LoggingAspect {
// // 声明该方法为一个前置通知:在目标方法开始之前执行
// @Before("execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(int, int))")
// public void beforeMethod(JoinPoint joinpoint) {
// String methodName = joinpoint.getSignature().getName();
// List<Object> args = Arrays.asList(joinpoint.getArgs());
// System.out.println("before method " + methodName + " with " + args);
// }
//
// // 声明该方法为一个后置通知:在目标方法结束之后执行(无论方法是否抛出异常)。
// // 但是因为当方法抛出异常时,不能返回值为null,因此这里无法获取到异常值。
// @After(value = "execution(public intcom.dx.spring.beans.aop.IArithmeticCalculator.*(int,int))")
// public void afterMethod(JoinPoint joinpoint) {
// String methodName = joinpoint.getSignature().getName();
// List<Object> args = Arrays.asList(joinpoint.getArgs());
// System.out.println("after method " + methodName);
// }
//
// /**
// * 声明该方法为一个返回通知:在目标方法返回结果时后执行(当方法抛出异常时,无法执行)。 但是因为当方法抛出异常时,类似代码 {@code
// * try <br/>
// * { <br/>
// * // before 前置通知 <br/>
// * // do action method <br/>
// * // after returning 返回通知,可以访问到方法的返回值 <br/>
// * } catch(Exception e){ e.printStackTrace(); // after throwing
// * 异常通知,可以访问到方法出现的异常 } // after 后置通知,因为方法可以抛出异常,所以访问不到方法的返回值 }
// */
// @AfterReturning(value = "execution(public intcom.dx.spring.beans.aop.IArithmeticCalculator.*(int,int))", returning = "result")
// public void afterReturningMethod(JoinPoint joinpoint, Object result) {
// String methodName = joinpoint.getSignature().getName();
// List<Object> args = Arrays.asList(joinpoint.getArgs());
// System.out.println(
// "after method " + methodName + " with returning " + (result == null ? "NULL" : result.toString()));
// }
//
// /**
// * 定义一个异常通知函数: 只有在方法跑吹异常时,该方法才会执行,而且可以接受异常对象。
// */
// @AfterThrowing(value = "execution(public intcom.dx.spring.beans.aop.IArithmeticCalculator.*(int,int))", throwing = "ex")
// public void afterThrowingMethod(JoinPoint joinpoint, Exception ex) {
// String methodName = joinpoint.getSignature().getName();
// List<Object> args = Arrays.asList(joinpoint.getArgs());
// System.out.println(
// "after method " + methodName + " occurs exception: " + (ex == null ? "NULL" : ex.getMessage()));
// } @Around(value = "execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(int, int))")
public Object aroundMethod(ProceedingJoinPoint pJoinPoint) throws Exception {
String methodName = pJoinPoint.getSignature().getName();
List<Object> args = Arrays.asList(pJoinPoint.getArgs()); Object result = null;
try {
// 前置通知
System.out.println("before method " + methodName + " with " + args);
// 执行目标方法
result = pJoinPoint.proceed();
// 返回通知
System.out.println("after method " + methodName + " returning " + result);
} catch (Throwable ex) {
// 异常通知
System.out.println("after method " + methodName + " occurs exception: " + ex.getMessage());
throw new Exception(ex);
}
// 后置通知
System.out.println("after method " + methodName);
return result;
}
}

修改Client.java测试类,添加代码:

        int result = arithmeticCalculator.add(1, 3);
System.out.println(result); result = arithmeticCalculator.div(4, 0);
System.out.println(result);

执行结果

Spring(十八):Spring AOP(二):通知(前置、后置、返回、异常、环绕)的更多相关文章

  1. AOP 环绕通知 集成了前置 后置 返回通知等功能

    AOP 环绕通知 集成了前置 后置 返回通知等功能

  2. Jmeter(十八) - 从入门到精通 - JMeter后置处理器 -下篇(详解教程)

    1.简介 后置处理器是在发出“取样器请求”之后执行一些操作.取样器用来模拟用户请求,有时候服务器的响应数据在后续请求中需要用到,我们的势必要对这些响应数据进行处理,后置处理器就是来完成这项工作的.例如 ...

  3. Spring AOP前置通知和后置通知

    Spring AOP AspectJ:Java社区里最完整最流行的AOP框架 在Spring2.0以上的版本中,可以使用基于AspectJ注解或基于XML配置的AOP 在Spring中启用Aspect ...

  4. spring 切面 前置后置通知 环绕通知demo

    环绕通知: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http:// ...

  5. Spring Bean前置后置处理器的使用

    Spirng中BeanPostProcessor和InstantiationAwareBeanPostProcessorAdapter两个接口都可以实现对bean前置后置处理的效果,那这次先讲解一下B ...

  6. NeHe OpenGL教程 第十八课:二次几何体

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  7. spring3: Aspectj后置返回通知

    Aspectj后置返回通知 接口: package chapter1.server; public interface IHelloService2 { public int sayAfterRetu ...

  8. pytest_前置后置

    今天总结下pytest,pytest简直就是python自动化中的高富帅,各种操作,哈哈 这次总结主要涉及到了以下几点: 1.unittest中的setUp.tearDown.setUpClass.t ...

  9. unittest的前置后置,pytest的fixture和共享机制conftest.py

    Unittest setUp/tearDown setUp当中得到的变量,用self.xxx = value传递给测试用例 setUpClass/tearDownClass setupClass当中得 ...

  10. [原创]java WEB学习笔记106:Spring学习---AOP的通知 :前置通知,后置通知,返回通知,异常通知,环绕通知

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

随机推荐

  1. Java中使用多线程、curl及代理IP模拟post提交和get访问

    Java中使用多线程.curl及代理IP模拟post提交和get访问 菜鸟,多线程好玩就写着玩,大神可以路过指教,小弟在这受教,谢谢! 更多分享请关注微信公众号:lvxing1788 ~~~~~~ 分 ...

  2. LPC43xx SGPIO Camera interface design

    AN11196: Camera interface design using SGPIO

  3. 标记 {x:Null},d:DesignWidth,d:DesignHeight

    {x:Null}:用于设置某属性值为Null,比如<Rectangle Fill="{x:Null}" />,其实就相当于<Rectangle />,个人感 ...

  4. Blocks Programming Topics

    最近的工作中比较频繁的用到了Block,不在是以前当做函数指针的替代或者某些API只有Blocks形式的接口才不得已用之了,发现自己对其了解还是太浅,特别是变量的生存期,按惯例还是翻译官方文档,原文链 ...

  5. 【GitLab】gitlab上配置webhook后,点击测试报错:Requests to the local network are not allowed

    gitlab上配置webhook后,点击测试报错: Requests to the local network are not allowed 操作如下: 报错: 错误原因: gitlab 10.6 ...

  6. PlaceholderTextView

    PlaceholderTextView 效果 源码 https://github.com/YouXianMing/UI-Component-Collection 的 PlaceholderTextVi ...

  7. C#程序集Assembly学习随笔(第一版)_AX

    ①什么是程序集?可以把程序集简单理解为你的.NET项目在编译后生成的*.exe或*.dll文件.嗯,这个确实简单了些,但我是这么理解的.详细:http://blog.csdn.net/sws8327/ ...

  8. Caffe的solver参数介绍

      版权声明:转载请注明出处,谢谢! https://blog.csdn.net/Quincuntial/article/details/59109447 1. Parameters solver.p ...

  9. glyphicons-halflings-regular.woff2:1 Failed to load resource: the server responded with a status of 404 (Not Found)解决Web部署 svg/woff/woff2字体 404错误

    问题:最近在IIS上部署web项目的时候,发现浏览器总是报找不到woff.woff2字体的错误.导致浏览器加载字体报404错误,白白消耗了100-200毫秒的加载时间. 原因:因为服务器IIS不认SV ...

  10. httpModules 不起作用 modules 不起作用 血泪经验

    本人也搜索了哏多解决方案.最后都没有解决... 劝您还会放弃把.. 如果非要用,劝您吧代码写到  Global.asax   里...(血泪经验)