AspectJ支持的5种类型的增强注解

前提:
①自定义一个有@Aspect注解修饰的切面类
②将其创建的对象保存于Spring IOC容器中
③自定义增强方法,增强方法也称为通知方法,指标注有@Before、@AfterRunning、@AfterThrowing、@After或@Around注解的Java方法。

目标类:CalculatorService.java

package com.jd.calculator;

import org.springframework.stereotype.Service;

@Service
public class CalculatorService implements ICalculatorService {

	@Override
	public int mul(int a, int b) {
		int result = a*b;
		if(result==1) {
			throw new ArithmeticException("两个数字的乘积不能为1");
		}
		return result;
	}

	@Override
	public int div(int a, int b) {
		int result = a/b;
		return result;
	}
}

接口:ICalculatorService.java

package com.jd.calculator;

public interface ICalculatorService {

    int mul(int a,int b);
	
	int div(int a,int b);
}

切面类:CalculatorAspect.java

package com.jd.calculator;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect//将该类声明为切面类
@Component/*将CalculatorAspect类创建对象并保存到Spring容器中*/
public class CalculatorAspect {

    //前置增强(又称前置通知)
	@Before("execution(int mul(..))")
	public void before(JoinPoint jp) {
		Object object = jp.getTarget();
		Object [] args = jp.getArgs();
		String name = jp.getSignature().getName();
		System.out.println(object.getClass().getName()+":The "+name+" method begins.");
		System.out.println(object.getClass().getName()+":Parameters of the "+name+" method: ["+args[0]+","+args[1]+"]");
	}
    
    //后置增强(又称后置通知)
	@AfterReturning(value="execution(int mul(..))",returning="a")
	public void afterReturning(JoinPoint jp,Object a) {
		Object object = jp.getTarget();
		String name = jp.getSignature().getName();
		System.out.println(object.getClass().getName()+":Result of the "+name+" method:"+a);
	}
	
	//返回增强(又称返回通知)
	@After("execution(int mul(..))")
	public void After(JoinPoint jp) {
		Object object = jp.getTarget();
		String name = jp.getSignature().getName();
		System.out.println(object.getClass().getName()+":The "+name+" method ends.");
	}
	
	//异常增强(又称异常通知)
	@AfterThrowing(value="execution(int mul(..))",throwing="e")
	public void afterThrowing(JoinPoint jp,Exception e) {
	//e变量数据类型为Exception,目标方法的异常为ArithmeticException时,因为异常是Exception的子类,所以目标方法出现异常时afterThrowing方法可以执行;如果e的数据类型为NullPointerException,则目标方法出现异常后afterThrowing方法不会执行
		Object object = jp.getTarget();
		String name = jp.getSignature().getName();
		System.out.println(object.getClass().getName()+":The "+name+" has a exception:"+e.getMessage());
	}
}

测试类:Test.java

package com.jd.test;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.jd.calculator.ICalculatorService;

public class Test {

	public static void main(String[] args) {
		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
		ICalculatorService calculatorService = applicationContext.getBean(ICalculatorService.class);
		System.out.println(calculatorService.getClass().getName());
		int result = calculatorService.mul(2, 1);
		System.out.println("——>"+result);
	}
}

一、增强注解

1、前置增强

  • 前置增强(又称前置通知):在目标方法执行之前执行。
	@Before("execution(int mul(..))")
	public void before(JoinPoint jp) {
		Object object = jp.getTarget();
		Object [] args = jp.getArgs();
		String name = jp.getSignature().getName();
		System.out.println(object.getClass().getName()+":The "+name+" method begins.");
		System.out.println(object.getClass().getName()+":Parameters of the "+name+" method: ["+args[0]+","+args[1]+"]");
	}

分析:
①jp.getTarget():获取对象;(在本例中结果为:com.jd.calculator.CalculatorService)
②jp.getArgs():获取方法中传入的参数值(在本例中是mul中传入的参数值);
③jp.getSignature().getName():获取对应方法名称(在本例中是mul)。

提醒:后面的所有增强中的这些语句的分析都一样!!!!


2、返回增强

  • 后置增强(又称后置通知):在目标方法执行后执行,无论目标方法运行期间是否出现异常。注意:后置增强无法获取目标方法执行结果,可以在返回增强中获取
	@AfterReturning(value="execution(int mul(..))",returning="a")
	public void afterReturning(JoinPoint jp,Object a) {
		Object object = jp.getTarget();
		String name = jp.getSignature().getName();
		System.out.println(object.getClass().getName()+":Result of the "+name+" method:"+a);
	}

3、异常增强

  • 返回增强(又称返回通知):在目标方法正常结束后执行,可以获取目标方法的执行结果
	@After("execution(int mul(..))")
	public void After(JoinPoint jp) {
		Object object = jp.getTarget();
		String name = jp.getSignature().getName();
		System.out.println(object.getClass().getName()+":The "+name+" method ends.");
	}

4、后置增强

  • 异常增强(又称异常通知):目标方法抛出异常之后执行,可以访问到异常对象,且可以指定在出现哪种异常时才执行增强代码
	@AfterThrowing(value="execution(int mul(..))",throwing="e")
	public void afterThrowing(JoinPoint jp,Exception e) {
		Object object = jp.getTarget();
		String name = jp.getSignature().getName();
		System.out.println(object.getClass().getName()+":The "+name+" has a exception:"+e.getMessage());
	}
}

分析:
(1) e变量数据类型为Exception,目标方法的异常为ArithmeticException时,因为异常是Exception的子类,所以目标方法出现异常时afterThrowing方法可以执行;
(2)如果e的数据类型为NullPointerException,则目标方法出现异常后afterThrowing方法不会执行


5、环绕增强

  • 增强注解——@Around,在@Around修饰的方法中可以实现@Before,@After,@AfterReturning和@AfterThrowing增强效果,可以实现动态代理全过程。
@Around(value="@annotation(org.springframework.transaction.annotation.Transactional)")
	public Object around(ProceedingJoinPoint jp) {
		Object result = null;
		Object object = jp.getTarget();
		String name = jp.getSignature().getName();
		Object [] args= jp.getArgs();
		try {
			try {
				//前置增强
				System.out.println(object.getClass().getName()+":The "+name+" method begins.");
				System.out.println(object.getClass().getName()+":Parameters of the "+name+" method: ["+args[0]+","+args[1]+"]");
				result = jp.proceed();//执行目标类中的目标方法
			}finally {
			    //后置增强	
				System.out.println(object.getClass().getName()+":The "+name+" method ends.");
			}
			//返回增强
			System.out.println(object.getClass().getName()+":Result of the "+name+" method:"+result);
		}catch (Throwable e) {
			//异常增强
			System.out.println(object.getClass().getName()+":The "+name+" has a exception:"+e.getMessage());
		}
		return result;
	}

二、分析

1、@Before,@After,@AfterReturning、@AfterThrowing的执行顺序

	try {
		try {
			doBefore();//@Before注解修饰的方法
			method.invoke();//执行目标对象内的方法
		}finally {
			doAfter();//@After注解修饰的方法
		}
		doAfterReturning();//@AfterReturning注解修饰的方法
	}catch(Exception e){
		doAfterThrowing();//@AfterThrowing注解修饰的方法
	}

2、代码的执行顺序

int result = calculatorService.mul(2, 1);

①、执行前置增强;②、执行目标对象的目标(mul)方法;③、执行后置增强;④、执行返回增强;⑤、如果前面方法出现异常,则执行异常增强

举例:

结果一:
com.sun.proxy.$Proxy13
com.jd.calculator.CalculatorService:The mul method begins.
com.jd.calculator.CalculatorService:Parameters of the mul method: [2,1]
com.jd.calculator.CalculatorService:The mul method ends.//后置增强
com.jd.calculator.CalculatorService:Result of the mul method:2//返回增强
——>2

结果二:
com.sun.proxy.$Proxy13
com.jd.calculator.CalculatorService:The mul method begins.
com.jd.calculator.CalculatorService:Parameters of the mul method: [1,1]
com.jd.calculator.CalculatorService:The mul method ends.
com.jd.calculator.CalculatorService:The mul has a exception:两个数字的乘积不能为1
Exception in thread “main” java.lang.ArithmeticException: 两个数字的乘积不能为1

3、5种增强的区别

(1)@Before、@After、@AfterRunning和@AfterThrowing修饰的方法可以通过声明JoinPoint 类型参数变量获取目标方法的信息(方法名、参数列表等信息);@Around修饰的方法必须声明ProceedingJoinPoint类型的参数,该变量可以决定是否执行目标方法;
(2)@Before、@After、@AfterRunning和@AfterThrowing修饰的方法没有返回值;而@Around修饰的方法必须有返回值,返回值为目标方法的返回值;

(4)总结

(1) 在执行环绕增强中的代码时,会先执行相当于前置增强的那段代码,然后执行result = jp.proceed(); 得到了目标方法的返回值;
(2)此时如果目标方法中抛出异常的话,会执行finally中的相当于后置增强的代码;
(3)接着就会执行catch中相当于异常增强的代码,而相当于返回增强的那部分代码不会执行。
(4)如果目标方法没有抛出异常的话,按照顺序执行,根据上述代码,就会出现上面提到的现象:后置增强输出结果顺序在返回增强之前,而且无论目标类方法是否抛出异常,相当于后置增强的代码都会执行。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值