Spring AOP通知

使用AspectJ代替Spring自带的Aop,在Spring中启用AspectJ注解支持需要以下导入Jar包:

      com.springsource.net.sf.cglib-2.20.jar(继承实现动态代理)

      com.springsource.org.aopalliance-1.0.0.jar

      com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar

      spring-aop-4.0.0.RELEASE.jar

      spring-aspects-4.0.0.RELEASE.jar

配置xml文件:


1 <!--组件扫描-->
2     <context:component-scan base-package="com.hxh.spring.aspectJ.annotation"/>
3     <!--基于注解使用AspectJ:主要作用是为切面中通知能作用到的目标类生成代理-->
4     <aop:aspectj-autoproxy/>
当Spring IOC容器检测到bean配置文件中的<aop:aspectj-autoproxy>时,会自动为AspectJ切面匹配的bean创建代理。

AspectJ支持的5种通知:  
  1. 前置通知(@Before)<在方法执行之前执行>
  2. 后置通知(@After)<在方法执行之后执行>
  3. 环绕通知(@Around)<围绕着方法进行>
  4. 异常通知(@AfterThrowing)<在方法抛出异常之后执行>
  5. 返回通知(@AfterRunning)<围绕着方法执行> 

前置和后置通知

 1 /**
 2  * 日志切面
 3  */
 4 @Component //标识为一个组件,交给Spring的IOC管理
 5 @Aspect//标识为一个切面
 6 public class LoggingAspect {
 7     /**
 8      * 前置通知:在目标方法(连接点)执行之前执行。
 9      *
10      */
11     //找到目标方法(方法可能会重写,故要把参数写出来,前置通知只作用在add方法)
12     @Before("execution(public int com.hxh.spring.aspectJ.annotation.mathCalculatorImpl.add(int,int))")
13     public void beforeMethod(JoinPoint joinPoint){
14     //方法前记录日志的通知
15         Object argss[]=joinPoint.getArgs();
16         String methodName=joinPoint.getSignature().getName();
17         //数组不好打印,转换成集合打印:格式为[,,,]
18         System.out.println("LoggingAspect--> The method "+methodName+"begin with "+ Arrays.asList(argss));
19     }
20     /**
21      * 后置通知:在目标方法执行之后执行,不管目标方法有没有抛出异常,不能获取方法的结果
22      * ..表示任意数量,任意类型的参数
23      * 第一个*表示任意修饰符,任意返回值
24      * 第二个*表示任意的类
25      * 第三个*表示任意方法
26      *
27      * 连接点对象:JoinPoint
28      */
29     @After("execution(* com.hxh.spring.aspectJ.annotation.*.*(..))")
30     public void afterMethod(JoinPoint joinPoint){
31         //获取方法的名字:
32         String methodName=joinPoint.getSignature().getName();
33         System.out.println("LoggingAspect--> The method "+methodName+"ends");
34     }
35 }

Main.java

 1 public class Main {
 2     public static void main(String[] args) {
 3         ApplicationContext ctx=
 4                 new ClassPathXmlApplicationContext("spring-aspectJ_annotation.xml");
 5 
 6         mathCalculator ac=ctx.getBean("mathCalculatorImpl",mathCalculator.class);//mathCalculatorImpl实现类
 7         System.out.println(ac);
 8         System.out.println(ac.getClass().getName());
 9         int result=ac.add(1,2);
10         System.out.println("result   :"+result);
11 
12 
13     }
14 }

运行结果

com.hxh.spring.aspectJ.annotation.mathCalculatorImpl@5c4b
com.sun.proxy.$Proxy8
LoggingAspect--> The method addbegin with [1, 2]
LoggingAspect--> The method addends
result   :3

返回通知和异常通知

 1 /**
 2      * 返回通知:在目标方法正常执行结束后执行(也就是说有异常的时候不会执行)可以获取到方法的返回值。
 3      *returning="xx",xx必须跟你方法中的一个形参名字一样,这样就会把返回值给到xx。
 4      */
 5     @AfterReturning(value = "execution(* com.hxh.spring.aspectJ.annotation.*.*(..))",returning = "result")
 6     public void afterReturningMethod(JoinPoint joinPoint,Object result){
 7         String methodName=joinPoint.getSignature().getName();
 8         System.out.println("LoggingAspect--> The method "+methodName+"end with "+result);
 9     }
10 
11     /**
12      * 异常通知:在目标方法抛出异常后执行
13      *
14      */
15     @AfterThrowing(value = "execution(* com.hxh.spring.aspectJ.annotation.*.*(..))",throwing = "ex")
16     public void afterThrowingMethod(JoinPoint joinPoint,Exception ex){
17         //方法的名字
18         String methodName=joinPoint.getSignature().getName();
19         System.out.println("LoggingAspect--> The method"+methodName+"occurs Exception: "+ex);
20     }

 

Main.java

        result=ac.div(5,0);//by zero异常
        System.out.println("result   :"+result);

 

运行结果

LoggingAspect--> The method divends 
Exception in thread "main" LoggingAspect--> The methoddivoccurs Exception: java.lang.ArithmeticException: / by zero

环绕通知(最强大)
 1 /**
 2      * 环绕通知:环绕着目标方法执行,可以理解为前置、后置、返回、异常通知的结合体,更像是动态代理的
 3      * 整个过程。
 4      *
 5      */
 6     @Around("execution(* com.hxh.spring.aspectJ.annotation.*.*(..))")
 7     public Object aroundMethod(ProceedingJoinPoint proceedingJoinPoint){
 8         //执行目标方法
 9         try {
10             //前置
11             Object result=proceedingJoinPoint.proceed();
12             //返回
13             return result;
14         } catch (Throwable throwable) {
15             //异常通知
16             throwable.printStackTrace();
17         }finally {
18             //后置通知
19         }
20         return null;
21     }

Tips:可以通过形参中异常的类型来设置抛出指定异常才会执行异常通知。比如说形参中写NullPointerException ex,只有
出现空指针异常才会执行异常通知。

ProceedingJoinPoin和joinPoint的关系
ProceedingJoinPoin extends joinPoint

Tips: @Order(1)//设置切面的优先级(int的最大值)2147483647,越小优先级越高
0x7fffffff 或者 Integer.MAX_VALUE可以表示int的最大值。二进制:01111111 11111111 11111111 11111111(高位是符号位,剩下的都是1)

@Pointcut("execution(* com.hxh.spring.aspectJ.annotation.*.*(..))")
public void declarePointCut(){}
这个切入点表达式可以用一个方法名来代替。例如:@AfterReturning(value="declarePointCut",returning="result")
在不同的类中使用方法名得申明是哪个类下的切入点表达式。例如在ValidationAspect.java中使用LoggingAspect中定义的切入点表达式 declarePointCut(){}
声明为:ValidationAspect.declarePointCut


posted @ 2019-05-17 17:09  单线程程序员  阅读(259)  评论(0编辑  收藏  举报