• Spring学习--用 ASpectJ 注解实现 AOP


    用 AspectJ 注解声明切面:

    • 要在 Spring 中声明 AspectJ 切面 , 只需要在 IOC 容器中将切面声明为 bean 实例。当在 Spring IOC 容器中初始化 AsjectJ 切面之后 , Spring IOC 容器就会为那些与 AspectJ 切面相匹配的 bean 创建代理。
    • 在 ApectJ 注解中 , 切面只是一个带有 @Asject 注解的 Java 类。
    • 通知是标注有某种注解的简单的 Java 方法。
    • AspectJ 支持 5 种类型的通知注解:
      1. @Before:前置通知 , 在方法执行之前执行。
      2. @After:后置通知 , 在方法执行之后执行。
      3. @AfterReturning:返回通知 , 在方法返回结果之后执行。
      4. @AfterThrowing:异常通知 , 在方法抛出异常之后。
      5. @Around:环绕通知 , 围绕着方法执行。

    前置通知:

     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:aop="http://www.springframework.org/schema/aop"
     5        xmlns:context="http://www.springframework.org/schema/context"
     6        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
     7        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
     8        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
     9 
    10     <!-- IOC 扫描包 -->
    11     <context:component-scan base-package="com.itdoc.spring.aop.impl"></context:component-scan>
    12     <!-- 使 AspectJ 注解起作用, 自动为匹配的类生成代理对象 -->
    13     <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    14 
    15 </beans>

    注意:一定要添加 aop 命名空间。

     1 package com.itdoc.spring.aop.impl;
     2 
     3 import org.springframework.stereotype.Component;
     4 
     5 /**
     6  * http://www.cnblogs.com/goodcheap
     7  *
     8  * @author: Wáng Chéng Dá
     9  * @create: 2017-03-03 19:34
    10  */
    11 @Component
    12 public interface Arithmetic {
    13 
    14     int add(int i, int j);
    15 
    16     int sub(int i, int j);
    17 
    18     int mul(int i, int j);
    19 
    20     int div(int i, int j);
    21 
    22 }
     1 package com.itdoc.spring.aop.impl;
     2 
     3 import org.springframework.stereotype.Component;
     4 
     5 /**
     6  * http://www.cnblogs.com/goodcheap
     7  *
     8  * @author: Wáng Chéng Dá
     9  * @create: 2017-03-03 19:35
    10  */
    11 @Component("arithmetic")
    12 public class ArithmeticImpl implements Arithmetic {
    13     @Override
    14     public int add(int i, int j) {
    15         int result = i + j;
    16         return result;
    17     }
    18 
    19     @Override
    20     public int sub(int i, int j) {
    21         int result = i - j;
    22         return result;
    23     }
    24 
    25     @Override
    26     public int mul(int i, int j) {
    27         int result = i * j;
    28         return result;
    29     }
    30 
    31     @Override
    32     public int div(int i, int j) {
    33         int result = i / j;
    34         return result;
    35     }
    36 }
     1 package com.itdoc.spring.aop.impl;
     2 
     3 
     4 import org.aspectj.lang.JoinPoint;
     5 import org.aspectj.lang.annotation.Aspect;
     6 import org.aspectj.lang.annotation.Before;
     7 import org.springframework.stereotype.Component;
     8 
     9 import java.util.Arrays;
    10 
    11 /**
    12  * http://www.cnblogs.com/goodcheap
    13  * 声明为一个切面的类: 需要把该类放到 IOC 容器中, 再声明为一个切面。
    14  * @author: Wáng Chéng Dá
    15  * @create: 2017-03-03 21:37
    16  */
    17 @Aspect
    18 @Component
    19 public class LoggingAspect {
    20 
    21     //声明该方法为前置通知: 在目标方法执行之前开始执行。
    22     @Before("execution(* com.itdoc.spring.aop.impl.*.*(..))")
    23     public void beforeMethod(JoinPoint joinPoint) {
    24         Object methodName = joinPoint.getSignature().getName();
    25         Object args = Arrays.asList(joinPoint.getArgs());
    26         System.out.println("The method " + methodName + " begins with " + args);
    27     }
    28 }

    @Before("execution(* com.itdoc.spring.aop.impl.*.*(..))")

    • 第一颗 * :代表任意修饰符 , 任意返回值。
    • 第二颗 * :代表任意对象。
    • 第三颗 * :代表任意方法。
    • 最后的 .. :代表任意参数。

    注意:在 AspectJ 中 , 切点表达式可以通过操作符 && , || , ! 结合起来。

     1 package com.itdoc.spring.aop.impl;
     2 
     3 import org.springframework.context.ApplicationContext;
     4 import org.springframework.context.support.ClassPathXmlApplicationContext;
     5 
     6 /**
     7  * http://www.cnblogs.com/goodcheap
     8  *
     9  * @author: Wáng Chéng Dá
    10  * @create: 2017-03-03 21:32
    11  */
    12 public class Main {
    13 
    14     public static void main(String[] args) {
    15 
    16         ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    17         Arithmetic arithmetic = (Arithmetic) ctx.getBean("arithmetic");
    18         System.out.println("result = " + arithmetic.add(9, 5));
    19         System.out.println("result = " + arithmetic.sub(9, 5));
    20     }
    21 }

    控制台输出:

    The method add begins with [9, 5]
    result = 14
    The method sub begins with [9, 5]
    result = 4

    后置通知:

    • 后置通知是在连接点完成之后执行的 , 即连接点返回结果或者抛出异常的时候。
    • 一个切面可以包括一个或者多个通知。
     1 package com.itdoc.spring.aop.impl;
     2 
     3 
     4 import org.aspectj.lang.JoinPoint;
     5 import org.aspectj.lang.annotation.After;
     6 import org.aspectj.lang.annotation.Aspect;
     7 import org.aspectj.lang.annotation.Before;
     8 import org.springframework.stereotype.Component;
     9 
    10 import java.util.Arrays;
    11 
    12 /**
    13  * http://www.cnblogs.com/goodcheap
    14  * 声明为一个切面的类: 需要把该类放到 IOC 容器中, 再声明为一个切面。
    15  * @author: Wáng Chéng Dá
    16  * @create: 2017-03-03 21:37
    17  */
    18 @Aspect
    19 @Component
    20 public class LoggingAspect {
    21 
    22     //声明该方法为前置通知: 在目标方法执行之前开始执行。
    23     @Before("execution(* com.itdoc.spring.aop.impl.*.*(..))")
    24     public void beforeMethod(JoinPoint joinPoint) {
    25         Object methodName = joinPoint.getSignature().getName();
    26         Object args = Arrays.asList(joinPoint.getArgs());
    27         System.out.println("The method " + methodName + " begins with " + args);
    28     }
    29 
    30     //声明该方法为后置通知: 在目标方法执行之后(无论是否发生异常)开始执行。
    31     @After("execution(* com.itdoc.spring.aop.impl.*.*(..))")
    32     public void afterMethod(JoinPoint joinPoint) {
    33         Object methodName = joinPoint.getSignature().getName();
    34         Object args = Arrays.asList(joinPoint.getArgs());
    35         System.out.println("The method " + methodName + " ends with " + args);
    36     }
    37 }
     1 package com.itdoc.spring.aop.impl;
     2 
     3 import org.springframework.context.ApplicationContext;
     4 import org.springframework.context.support.ClassPathXmlApplicationContext;
     5 
     6 /**
     7  * http://www.cnblogs.com/goodcheap
     8  *
     9  * @author: Wáng Chéng Dá
    10  * @create: 2017-03-03 21:32
    11  */
    12 public class Main {
    13 
    14     public static void main(String[] args) {
    15 
    16         ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    17         Arithmetic arithmetic = (Arithmetic) ctx.getBean("arithmetic");
    18         System.out.println("result = " + arithmetic.add(9, 5));
    19         System.out.println("result = " + arithmetic.div(9, 0));
    20     }
    21 }

    控制台输出:

    Exception in thread "main" java.lang.ArithmeticException: / by zero
    at com.itdoc.spring.aop.impl.ArithmeticImpl.div(ArithmeticImpl.java:33)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
    at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:52)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.aspectj.AspectJAfterAdvice.invoke(AspectJAfterAdvice.java:43)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
    at com.sun.proxy.$Proxy8.div(Unknown Source)
    at com.itdoc.spring.aop.impl.Main.main(Main.java:19)
    The method add begins with [9, 5]
    The method add ends with [9, 5]
    result = 14
    The method div begins with [9, 0]
    The method div ends with [9, 0]

    返回通知:

    无论连接点是正常返回还是抛出异常 , 后置通知都会执行。如果只想在连接点返回的时候记录日志 , 应使用返回通知代替后置通知。

     1 package com.itdoc.spring.aop.circular;
     2 
     3 import org.aspectj.lang.JoinPoint;
     4 import org.aspectj.lang.annotation.AfterReturning;
     5 import org.aspectj.lang.annotation.Aspect;
     6 import org.springframework.stereotype.Component;
     7 
     8 /**
     9  * 通知
    10  * http://www.cnblogs.com/goodcheap
    11  *
    12  * @author: Wáng Chéng Dá
    13  * @create: 2017-03-04 9:50
    14  */
    15 @Aspect
    16 @Component
    17 public class AsjectLogging {
    18 
    19     /**
    20      * 在方法正常结束后执行代码。
    21      * 返回通知是可以访问到方法的返回值的。
    22      */
    23     @AfterReturning(value = "execution(* com.itdoc.spring.aop.circular.*.*(..))", returning = "result")
    24     public void afterReturning(JoinPoint joinPoint, Object result) {
    25         Object methodName = joinPoint.getSignature().getName();
    26         System.out.println("The method " + methodName + " ends with " + result);
    27     }
    28 }

    异常通知:

     1 package com.itdoc.spring.aop.circular;
     2 
     3 import org.aspectj.lang.JoinPoint;
     4 import org.aspectj.lang.annotation.AfterReturning;
     5 import org.aspectj.lang.annotation.AfterThrowing;
     6 import org.aspectj.lang.annotation.Aspect;
     7 import org.springframework.stereotype.Component;
     8 
     9 /**
    10  * 通知
    11  * http://www.cnblogs.com/goodcheap
    12  *
    13  * @author: Wáng Chéng Dá
    14  * @create: 2017-03-04 9:50
    15  */
    16 @Aspect
    17 @Component
    18 public class AsjectLogging {
    19 
    20     /**
    21      * 在目标方法出现异常时候执行的代码。
    22      * 可以访问到异常对象, 且可以指定在出现特定异常时再执行的代码。
    23      */
    24     @AfterThrowing(value = "execution(* com.itdoc.spring.aop.circular.*.*(..))", throwing = "e")
    25     public void afterThrowing(JoinPoint joinPoint, Exception e) {
    26         Object methodName = joinPoint.getSignature().getName();
    27         System.out.println("The method " + methodName + " exception with " + e);
    28     }
    29 }

    环绕通知:

     1 package com.itdoc.spring.aop.circular;
     2 
     3 import org.aspectj.lang.ProceedingJoinPoint;
     4 import org.aspectj.lang.annotation.Around;
     5 import org.aspectj.lang.annotation.Aspect;
     6 import org.springframework.stereotype.Component;
     7 
     8 import java.util.Arrays;
     9 
    10 /**
    11  * 通知
    12  * http://www.cnblogs.com/goodcheap
    13  *
    14  * @author: Wáng Chéng Dá
    15  * @create: 2017-03-04 9:50
    16  */
    17 @Aspect
    18 @Component
    19 public class AsjectLogging {
    20 
    21     /**
    22      * 环绕通知需携带 ProceedingJoinPoint 类型的参数。
    23      * 环绕通知类似于动态代理的全过程: ProceedingJoinPoint 类型参数可以决定是否执行目标方法。
    24      * 环绕通知必须有返回值, 返回值即目标方法的返回值。
    25      *
    26      * @param point
    27      * @return
    28      */
    29     @Around("execution(* com.itdoc.spring.aop.circular.*.*(..))")
    30     public Object around(ProceedingJoinPoint point) {
    31         Object methodName = point.getSignature().getName();
    32         Object[] args = point.getArgs();
    33         Object result = null;
    34         try {
    35             //前置通知
    36             System.out.println("The method " + methodName + " begins with" + Arrays.asList(args));
    37             //执行方法
    38             result = point.proceed();
    39             //返回通知
    40             System.out.println("The method " + methodName + " ends with " + result);
    41         } catch (Throwable e) {
    42             e.printStackTrace();
    43             //异常通知
    44             System.out.println("The method " + methodName + " exception with " + e);
    45         } finally {
    46             //后置通知
    47             System.out.println("The method " + methodName + " ends");
    48         }
    49         return result;
    50     }
    51 }
  • 相关阅读:
    网络拓扑
    OSI 7层模型和TCP/IP 4层模型
    第一范式 第二范式 第三范式 BC范式 第四范式
    医院 信息科
    李纳斯•托瓦兹
    所谓绅士,就是做自己该做之事,而不是想做之事。
    活着
    开头词
    人际题目
    人际关系
  • 原文地址:https://www.cnblogs.com/chinda/p/6500393.html
Copyright © 2020-2023  润新知