Spring AOP中 前置、后置、返回、异常、环绕通知的实例

怼烎@ 2022-04-06 01:37 423阅读 0赞

1 在Spring中启用AspectJ注解支持
  要在Spring应用中使用AspectJ注解,必须在classpath下包含AspectJ类库:aopalliance.jar、aspectj.weaver.jar和spring-aspects.jar
  将aop Schema添加到根元素中。
  要在Spring IOC容器中启用AspectJ注解支持,只要早bean配置文件中定义一个空的XML元素
  当Spring IOC容器侦测到bean配置文件中的元素时,会自动为与AspectJ切面匹配的bean创建代理
2 用AspectJ注解声明切面
  要在Spring中声明AspectJ切面,只需要在IOC容器中将切面声明为bean实例。当在Spring IOC容器中初始化AspectJ切面之后,Spring IOC容器就会为那些与AspectJ切面相匹配的bean创建代理
  在AspectJ注解中,切面只是一个带有@AspectJ注解的Java类
  通知是标注有某种注解的简单的Java方法
  AspectJ支持5种类型的通知注解:
    @Before:前置通知,在方法执行之前返回
    @After:后置通知,在方法执行后执行
    @AfterRunning:返回通知,在方法返回结果之后执行
    @AfterThrowing:异常通知,在方法抛出异常之后
    @Around:环绕通知,围绕着方法执行

下面我们来看一个实例:

ArithmeticCalculator接口:

  1. package com.primary.spring.aop;
  2. public interface ArithmeticCalculator {
  3. int add(int i, int j);
  4. int sub(int i, int j);
  5. int mul(int i, int j);
  6. int div(int i, int j);
  7. }

ArithmeticCalculator的实现类 ArithmeticCalculatorImpl:

  1. package com.primary.spring.aop;
  2. import org.springframework.stereotype.Component;
  3. @Component
  4. public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
  5. @Override
  6. public int add(int i, int j) {
  7. int result = i + j;
  8. return result;
  9. }
  10. @Override
  11. public int sub(int i, int j) {
  12. int result = i - j;
  13. return result;
  14. }
  15. @Override
  16. public int mul(int i, int j) {
  17. int result = i * j;
  18. return result;
  19. }
  20. @Override
  21. public int div(int i, int j) {
  22. int result = i / j;
  23. return result;
  24. }
  25. }

配置自动扫描的包和配置自动为匹配aspectJ 注解的java类生成代理对象的xml文件:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xmlns:aop="http://www.springframework.org/schema/aop"
  6. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  7. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
  8. http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
  9. <!-- 配置自动扫描的包 -->
  10. <context:component-scan base-package="com.primary.spring.aop"></context:component-scan>
  11. <!-- 配置自动为匹配aspectJ 注解的java类生成代理对象 -->
  12. <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
  13. </beans>

@Pointcut切点表达式 :后面的其他通知直接使用方法名来引用当前切入点的表达式

  1. /**
  2. * 切入点表达式的声明,一般地,该方法中不需要再添加其他代码
  3. * 使用@Pointcut来声明切入点表达式
  4. * 后面的其他通知直接使用方法名来引用当前切入点的表达式
  5. */
  6. @Pointcut("execution(* com.primary.spring.aop.*.*(..))")
  7. public void declareJointPointExpression() {}

@Before:前置通知,在方法执行之前返回

  1. /**
  2. *前置通知:声明该方法是一个前置通知:在目标方法开始之前执行
  3. * @param joinPoint
  4. */
  5. @Before("declareJointPointExpression()")
  6. public void beforeMethod(JoinPoint joinPoint) {
  7. // 在通知的方法中声明一个类型为JoinPoint的参数, 然后就可以访问链接细节,如方法和参数值。
  8. String methodName = joinPoint.getSignature().getName();
  9. List<Object> args = Arrays.asList(joinPoint.getArgs());
  10. System.out.println("The methed " + methodName + " begins with " + args);
  11. }

@After:后置通知,在方法执行后执行

  1. /**
  2. * 后置通知:声明该方法是一个后置通知:在目标方法执行后(无论该方法是否发生异常), 一定会打印通知.
  3. * 在后置通知中不能访问目标方法执行的结果
  4. * @param joinPoint
  5. */
  6. @After("declareJointPointExpression()")
  7. public void AfterMethod(JoinPoint joinPoint) {
  8. String methodName = joinPoint.getSignature().getName();
  9. System.out.println("The methed " + methodName + " ends");
  10. }

@AfterRunning:返回通知,在方法返回结果之后执行

  1. /**
  2. *返回通知:在方法正常结束后执行的代码, 返回通知是可以访问到方法的返回值的!
  3. * @param joinPoint
  4. * @param result
  5. */
  6. @AfterReturning(value = "declareJointPointExpression()",
  7. returning="result")
  8. public void afterReturning(JoinPoint joinPoint, Object result) {
  9. String methodName = joinPoint.getSignature().getName();
  10. System.out.println("The methed " + methodName + " return with " + result);
  11. }

@AfterThrowing:异常通知,在方法抛出异常之后

  1. /**
  2. * 异常通知:在目标方法出现异常时会执行的代码
  3. * 可以访问到异常对象,且可以指定在出现特定异常时执行通知代码
  4. * @param joinPoint
  5. * @param e
  6. */
  7. @AfterThrowing(value = "declareJointPointExpression()",
  8. throwing="e")
  9. public void afterThrowing(JoinPoint joinPoint,Exception e) {
  10. String methodName = joinPoint.getSignature().getName();
  11. System.out.println("The methed " + methodName + " occurs excetion " + e);
  12. }

@Around:环绕通知,围绕着方法执行:环绕通知类似于动态代理全过程即综合了(前置、后置、返回、异常通知)为一体的通知:

  1. /**
  2. * 环绕通知:需要携带ProceedingJoinPoint 类型的参数
  3. * 环绕通知类似于动态代理全过程即综合了(前置、后置、返回、异常通知)为一体的通知:ProceedingJoinPoint 类型的参数可以决定是否执行目标方法
  4. * 且环绕通知必须要有返回值,返回值即为目标方法的返回值
  5. * @param proceedingJoinPoint
  6. * @return
  7. */
  8. @Around("execution(* com.primary.spring.aop.*.*(..))")
  9. public Object aroundMethod(ProceedingJoinPoint proceedingJoinPoint) {
  10. Object result = null;
  11. String methodName = proceedingJoinPoint.getSignature().getName();
  12. //执行目标方法
  13. try {
  14. //前置通知
  15. System.out.println("The method " + methodName + " begins with " + Arrays.asList(proceedingJoinPoint.getArgs()));
  16. result = proceedingJoinPoint.proceed();
  17. //返回通知
  18. System.out.println("The method "+ methodName + " return with " + result);
  19. } catch (Throwable e) {
  20. e.printStackTrace();
  21. //异常通知
  22. System.out.println("The method "+ methodName + " occurs exception: " + e);
  23. }
  24. //后置通知
  25. System.out.println("The method " + methodName + " ends");
  26. return result;
  27. }

测试方法:

  1. package com.primary.spring.aop;
  2. import org.springframework.context.ApplicationContext;
  3. import org.springframework.context.support.ClassPathXmlApplicationContext;
  4. public class Main {
  5. public static void main(String[] args) {
  6. //1 .创建Spring的IOC容器
  7. ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
  8. //2. 从IOC容器中获取bean的实例
  9. ArithmeticCalculator arithmeticCalculator = ctx.getBean(ArithmeticCalculator.class);
  10. //3. 使用bean
  11. int result = arithmeticCalculator.add(3, 4);
  12. System.out.println("result: " + result);
  13. result = arithmeticCalculator.div(3, 1);
  14. System.out.println("result: " + result);
  15. }
  16. }

我们发现用@Before、@After、@AfterRunning、@AfterThrowing执行的效果和单独使用@Around通知效果一样,但不等于环绕通知一定好于前面的四种通知:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dhbmdqaWFuNTMw_size_16_color_FFFFFF_t_70

发表评论

表情:
评论列表 (有 0 条评论,423人围观)

还没有评论,来说两句吧...

相关阅读