Spring入门学习(AOP返回通知&异常通知&环绕通知&切面的优先级) 第十六节

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011171125/article/details/85849715

Spring入门学习(AOP返回通知&异常通知&环绕通知)

返回通知

使用`@AfterReturning`注解,在方法正常结束后执行的通知,它是可以获得方法的返回值的。
  • LoggingAspect类中添加如下方法:
    /**
     * 在方法正常结束后执行的代码
     * 返回通知是可以访问到方法的返回值的
     * @param joinPoint
     */
    @AfterReturning(value="execution(* *.*(..))",returning="result")
    public void afterReturning(JoinPoint joinPoint, Object result){
    	String methodName = joinPoint.getSignature().getName();
    	System.out.println("The method "+methodName+ " ends with "+result);
    }
    
    使用@AfterReturning注解,注解中的returning获取返回值。
    测试结果:
    com.sun.proxy.$Proxy10
    The methodadd begins...[3, 6]
    The method add ends...
    The method add ends with 9
    result:9
    The methoddiv begins...[6, 3]
    The method div ends...
    The method div ends with 2
    result:2
    

异常通知

使用`@AfterThrowing`注解,在目标方法出现异常时会执行的代码,可以访问到异常对象;且可以指定在出现特定异常时在执行通知代码
  • LoggingAspect类中添加afterThrowing方法:
    /**
     * 在目标方法出现异常时会执行的代码
     * 可以访问到异常对象;且可以指定在出现特定异常时在执行通知代码
     * @param joinPoint
     * @param ex
     */
    @AfterThrowing(value="execution(* *.*(..))",throwing="ex")
    public void afterThrowing(JoinPoint joinPoint, Exception ex){
    	String methodName = joinPoint.getSignature().getName();
    	System.out.println("The method "+methodName+ " occurs exception: "+ex);
    }
    
  • 测试:
    测试方法:
    public class Main {
    
    	public static void main(String[] args) {
    		ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath*:applicationContext.xml");
    		ArithmeticCalculator arithmeticCalculator = ctx.getBean(ArithmeticCalculator.class);
    		System.out.println(arithmeticCalculator.getClass().getName());
    		
    		int result = arithmeticCalculator.add(3, 6);
    		System.out.println("result:" + result);
    	
    		result = arithmeticCalculator.div(6, 3);
    		System.out.println("result:" + result);
    		
    		result = arithmeticCalculator.div(6, 0);
    		System.out.println("result:" + result);
    	}
    }
    
    测试结果:
    com.sun.proxy.$Proxy11
    The methodadd begins...[3, 6]
    The method add ends...
    The method add ends with 9
    result:9
    The methoddiv begins...[6, 3]
    The method div ends...
    The method div ends with 2
    result:2
    The methoddiv begins...[6, 0]
    The method div ends...
    The method div occurs exception: java.lang.ArithmeticException: / by zero
    Exception in thread "main" java.lang.ArithmeticException: / by zero
    	at com.fafa.spring.aop.impl.ArithmeticCalculatorImpl.div(ArithmeticCalculatorImpl.java:35)
    	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.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:52)
    	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    	at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:58)
    	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.$Proxy11.div(Unknown Source)
    	at com.fafa.spring.aop.impl.Main.main(Main.java:19)
    

环绕通知

  • 使用@Around注解;
  • 环绕通知需要携带ProceedingJoinPoint类型的参数;
  • 环绕通知类似于动态代理的全过程:ProceedingJoinPoint这个类型的参数可以决定是否执行目标方法;
  • 且环绕通知必须有返回值,返回值即为有目标方法的返回值。
  1. 注释掉LoggingAspect类中的其它的方法,添加如下方法:
    	/**
    	 * 环绕通知需要携带ProceedingJoinPoint类型的参数。
    	 * 环绕通知类似于动态代理的全过程:ProceedingJoinPoint这个类型的参数可以决定是否执行目标方法。
    	 * 且环绕通知必须有返回值,返回值即为有目标方法的返回值
    	 * @param proceedingJoinPoint
    	 */
    	@Around(value="execution(* *.*(..))")
    	public Object aroundMethd(ProceedingJoinPoint pjd){
    		String methodName = pjd.getSignature().getName();
    		Object result = null;
    		try {
    			// 前置通知
    			System.out.println("The method "+methodName+ " begins");
    			result = pjd.proceed();
    			// 返回通知
    			System.out.println("The method "+methodName+" ends with "+result);
    		} catch (Throwable e) {
    			// 异常通知
    			System.out.println("The method "+methodName+ " occurs exception: "+e);
    			e.printStackTrace();
    		}
    		// 后置通知
    		System.out.println("The method "+methodName+ " ends ");
    		return result;
    	}
    
  2. 测试(去掉除0的):
    com.sun.proxy.$Proxy8
    The method add begins
    The method add ends with 9
    The method add ends 
    result:9
    The method div begins
    The method div ends with 2
    The method div ends 
    result:2
    
    可见环绕通知和动态代理是非常类似的,可以控制到方法是否执行,方法的返回值。

切面的优先级

  1. 此时我们再定义一个切面类ValidationAspect:
    @Component
    @Aspect
    public class ValidationAspect {
    
    	@Before("execution(public int com.fafa.spring.aop.impl.ArithmeticCalculator.*(int,int))")
    	public void validateArgs(JoinPoint joinPoint){
    		System.out.println("-->validate:"+Arrays.asList(joinPoint.getArgs()));
    	}
    }
    
  2. 注释掉LoggingAspect类中的aroundMethd方法
  3. 执行main方法:
    com.sun.proxy.$Proxy10
    The methodadd begins...[3, 6]
    -->validate:[3, 6]
    The method add ends...
    The method add ends with 9
    result:9
    The methoddiv begins...[6, 3]
    -->validate:[6, 3]
    The method div ends...
    The method div ends with 2
    result:2
    
    从结果看两个切面类中@Before都执行了,但是我们如果要控制它们的顺序该怎么办;
  4. 此时可以在切面类上使用@Order注解指定切面的优先级,值越小优先级越高:
    @Component
    @Aspect
    @Order(1)
    public class ValidationAspect {
    	@Before("execution(public int com.fafa.spring.aop.impl.ArithmeticCalculator.*(int,int))")
    	public void validateArgs(JoinPoint joinPoint){
    		System.out.println("-->validate:"+Arrays.asList(joinPoint.getArgs()));
    	}
    }
    
    // 把这个类声明为一个切面: 需要把该类放入到IOC容器中,再声明为一个切面
    @Component
    @Aspect
    @Order(2)	//使用Order指定切面的优先级,值越小优先级越高
    public class LoggingAspect {
    
    // 声明该方法是一个前置通知:在目标方法开始之前执行
    //	@Before("execution(public int com.fafa.spring.aop.impl.ArithmeticCalculator.add(int, int))")
    	@Before("execution(* com.fafa.spring.aop.impl.*.*(int, int))")
    	public void beforeMethod(JoinPoint joinPoint) {
    		String methodName = joinPoint.getSignature().getName();
    		List<Object> args = Arrays.asList(joinPoint.getArgs());
    		System.out.println("The method" + methodName +" begins..." + args);
    	}
    	
    	// 后置通知就是在目标方法执行后(无论是否发生异常),都会执行的通知
    	// 在后置通知中还不能访问目标方法执行的结果。
    	@After("execution(* com.fafa.spring.aop.impl.*.*(..))")
    	public void afterMethod(JoinPoint joinPoint) {
    		String methodName = joinPoint.getSignature().getName();
    		System.out.println("The method "+methodName+" ends...");
    	}
    	
    	/**
    	 * 在方法正常结束后执行的代码
    	 * 返回通知是可以访问到方法的返回值的
    	 * @param joinPoint
    	 */
    	@AfterReturning(value="execution(* *.*(..))",returning="result")
    	public void afterReturning(JoinPoint joinPoint, Object result){
    		String methodName = joinPoint.getSignature().getName();
    		System.out.println("The method "+methodName+ " ends with "+result);
    	}
    	
    	/**
    	 * 在目标方法出现异常时会执行的代码
    	 * 可以访问到异常对象;且可以指定在出现特定异常时在执行通知代码
    	 * @param joinPoint
    	 * @param ex
    	 */
    	@AfterThrowing(value="execution(* *.*(..))",throwing="ex")
    	public void afterThrowing(JoinPoint joinPoint, Exception ex){
    		String methodName = joinPoint.getSignature().getName();
    		System.out.println("The method "+methodName+ " occurs exception: "+ex);
    	}
    	
    	/**
    	 * 环绕通知需要携带ProceedingJoinPoint类型的参数。
    	 * 环绕通知类似于动态代理的全过程:ProceedingJoinPoint这个类型的参数可以决定是否执行目标方法。
    	 * 且环绕通知必须有返回值,返回值即为有目标方法的返回值
    	 * @param proceedingJoinPoint
    	 */
    	/*@Around(value="execution(* *.*(..))")
    	public Object aroundMethd(ProceedingJoinPoint pjd){
    		String methodName = pjd.getSignature().getName();
    		Object result = null;
    		try {
    			// 前置通知
    			System.out.println("The method "+methodName+ " begins");
    			result = pjd.proceed();
    			// 返回通知
    			System.out.println("The method "+methodName+" ends with "+result);
    		} catch (Throwable e) {
    			// 异常通知
    			System.out.println("The method "+methodName+ " occurs exception: "+e);
    			e.printStackTrace();
    		}
    		// 后置通知
    		System.out.println("The method "+methodName+ " ends ");
    		return result;
    	}*/
    }
    
  5. 执行测试结果返回如下:
    com.sun.proxy.$Proxy11
    -->validate:[3, 6]
    The methodadd begins...[3, 6]
    The method add ends...
    The method add ends with 9
    result:9
    -->validate:[6, 3]
    The methoddiv begins...[6, 3]
    The method div ends...
    The method div ends with 2
    result:2
    

猜你喜欢

转载自blog.csdn.net/u011171125/article/details/85849715
今日推荐