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

源代码

  1. CalculatorService类
    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;
    		return result;
    	}
    
    	@Override
    	public int div(int a, int b) {
    		int result = a/b;
    		return result;
    	}
    }
    
  2. CalculatorService类所实现的接口ICalculatorService
    package com.jd.calculator;
    
    public interface ICalculatorService {
    	
    	public int mul(int a, int b);
    	
    	public int div(int a, int b);
    }
    
  3. @Aspect修饰的切面类Calculator
    package com.jd.calculator;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.AfterReturning;
    import org.aspectj.lang.annotation.AfterThrowing;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.springframework.stereotype.Component;
    
    @Aspect
    @Component
    public class Calculator {
    	
    	@Before("execution(int mul(int, int))")
    	public void begin(JoinPoint jp) {
    		Object obj = jp.getTarget();
    		Object[] args = jp.getArgs();
    		String name = jp.getSignature().getName().toString();
    		System.out.println(obj.getClass().getName()+":The "+name+" method begins.");
    		System.out.println(obj.getClass().getName()+":Parameters of the "+name+" method: ["+args[0]+","+args[1]+"]");
    	}
    	
    	@AfterReturning(value="execution(int mul(int, int))",returning="result")
    	public void afterReturning(JoinPoint jp, Object result) {
    		Object obj = jp.getTarget();
    		String name = jp.getSignature().getName().toString();
    		System.out.println(obj.getClass().getName()+": The result of the "+name+" method is "+result);
    	}
    	
    	@After("execution(int mul(int, int))")
    	public void after(JoinPoint jp) {
    		Object obj = jp.getTarget();
    		String name = jp.getSignature().getName().toString();
    		System.out.println(obj.getClass().getName()+":The "+name+" method ends.");
    	}
    	
    	@AfterThrowing(value="execution(int mul(int, int))", throwing="e")
    	public void afterThrowing(JoinPoint jp, NullPointerException e) {
    		Object obj = jp.getTarget();
    		String name = jp.getSignature().getName().toString();
    		System.out.println(obj.getClass().getName()+":The "+name+" method has a exception:"+e.getMessage());
    	}
    	
    	@Around("execution(int mul(int,int))")
    	public Object around(ProceedingJoinPoint jp) {
    		Object result = null;
    		Object obj = jp.getTarget();
    		Object[] args = jp.getArgs();
    		String name = jp.getSignature().getName().toString();
    		try {
    			try {
    				//前置增强
    				System.out.println(obj.getClass().getName()+":The "+name+" method begins.");
    				System.out.println(obj.getClass().getName()+":Parameters of the "+name+" method: ["+args[0]+","+args[1]+"]");
    				//执行目标类中的方法
    				result = jp.proceed();
    			} finally {
    				//后置增强
    				System.out.println(obj.getClass().getName()+":The "+name+" method ends.");
    			}
    			//返回增强
    			System.out.println(obj.getClass().getName()+": The result of the "+name+" method is "+result);
    		} catch (Throwable e) {
    			//异常增强
    			System.out.println(obj.getClass().getName()+":The "+name+" method has a exception:"+e.getMessage());
    		}
    		return result;
    	}
    }
    
  4. application.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xmlns:aop="http://www.springframework.org/schema/aop"
    	xmlns:context="http://www.springframework.org/schema/context"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
    		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
    
    	<context:component-scan base-package="com.jd"></context:component-scan>
    	
    	<!-- autoproxy:Spring寻找@Aspect类(CalculatorAspect)——>寻找该类中方法——>获取方法注解 ——> 获取表达式(execution(int mul(int a, int b))——>检查Spring能扫描到的所有类,将与表达式匹配的方法对应的类——>为该类创建动态对象-->
    	<aop:aspectj-autoproxy proxy-target-class="false"></aop:aspectj-autoproxy>
    </beans>
    
  5. 测试类Test
    package com.jd.test;
    
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import com.jd.calculator.CalculatorService;
    import com.jd.calculator.ICalculatorService;
    
    public class Test {
    
    	public static void main(String[] args) {
    		@SuppressWarnings("resource")
    		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
    		ICalculatorService calculatorService = applicationContext.getBean(ICalculatorService.class);
    		int result = calculatorService.mul(1, 1);
    		System.out.println("-->"+result);
    	}
    }
    

1. 前置增强@Before(又称前置通知)

在目标方法执行之前执行

示例:

@Before("execution(int mul(int, int))")
public void begin(JoinPoint jp) {
	Object obj = jp.getTarget();
	Object[] args = jp.getArgs();
	String name = jp.getSignature().getName().toString();
	System.out.println(obj.getClass().getName()+":The "+name+" method begins.");
	System.out.println(obj.getClass().getName()+":Parameters of the "+name+" method: ["+args[0]+","+args[1]+"]");
}

测试类执行结果:

com.jd.calculator.CalculatorService:The mul method begins.
com.jd.calculator.CalculatorService:Parameters of the mul method: [1,1]
–>1


2. 后置增强@After(又称后置通知)

在目标方法执行后执行,无论目标方法运行期间是否出现异常都会执行。注意:后置增强无法获取目标方法执行结果,可以在返回增强中获取。

示例:

@After("execution(int mul(int, int))")
public void after(JoinPoint jp) {
	Object obj = jp.getTarget();
	String name = jp.getSignature().getName().toString();
	System.out.println(obj.getClass().getName()+":The "+name+" method ends.");
}

测试类执行结果( begin(JoinPoint jp)方法未注释掉):

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.
–>1

3. 返回增强@AfterReturning(又称返回通知)

在目标方法正常结束后执行,可以获取目标方法的执行结果,如果目标方法运行期间出现异常,则不会执行返回增强。

示例:

@AfterReturning(value="execution(int mul(int, int))",returning="result")
public void afterReturning(JoinPoint jp, Object result) {
	Object obj = jp.getTarget();
	String name = jp.getSignature().getName().toString();
	System.out.println(obj.getClass().getName()+": The result of the "+name+" method is "+result);
}

测试类执行结果( begin(JoinPoint jp)方法和after(JoinPoint jp)方法未注释掉):

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 result of the mul method is 1
–>1

4. 异常增强@AfterThrowing(又称异常通知)

目标方法抛出异常之后执行,可以访问到异常对象,且可以指定在出现哪种异常时才执行增强代码。

注意: 异常增强注解的方法的第二个参数必须是出现的异常的同类或其父类才会执行增强代码。

示例:

@AfterThrowing(value="execution(int mul(int, int))", throwing="e")
public void afterThrowing(JoinPoint jp, ArithmeticException e) {
	Object obj = jp.getTarget();
	String name = jp.getSignature().getName().toString();
	System.out.println(obj.getClass().getName()+":The "+name+" method has a exception:"+e.getMessage());
}

CalculatorService类中mul(int a, int b)方法修改如下:

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

测试类Test中mul方法传参为0,1

测试类执行结果( begin(JoinPoint jp)方法、after(JoinPoint jp)方法、afterReturning(JoinPoint jp, Object result)未注释掉):

com.jd.calculator.CalculatorService:The mul method begins.
com.jd.calculator.CalculatorService:Parameters of the mul method: [0,1]
com.jd.calculator.CalculatorService:The mul method ends.
com.jd.calculator.CalculatorService:The mul method has a exception:两数的乘积不能为0!


5. @Before,@After,@AfterReturning,@AfterThrowing执行顺序

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

即先执行前置增强,然后执行目标对象内的方法。如果方法执行过程中出现异常,则执行finally代码块中的后置增强,然后执行catch代码块中的异常增强;如果方法执行过程中没有出现异常,则执行finally代码块中的后置增强,然后执行返回增强。

6. 环绕增强@Around(又称环绕通知)

在@Around修饰的方法中可以实现@Before,@After,@AfterReturning和@AfterThrowing增强效果,可以实现动态代理全过程。

注意:

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

示例:

@Around("execution(int mul(int,int))")
public Object around(ProceedingJoinPoint jp) {
	Object result = null;
	Object obj = jp.getTarget();
	Object[] args = jp.getArgs();
	String name = jp.getSignature().getName().toString();
	try {
		try {
			//前置增强
			System.out.println(obj.getClass().getName()+":The "+name+" method begins.");
			System.out.println(obj.getClass().getName()+":Parameters of the "+name+" method: ["+args[0]+","+args[1]+"]");
			//执行目标类中的方法
			result = jp.proceed();
		} finally {
			//后置增强
			System.out.println(obj.getClass().getName()+":The "+name+" method ends.");
		}
		//返回增强
		System.out.println(obj.getClass().getName()+": The result of the "+name+" method is "+result);
	} catch (Throwable e) {
		//异常增强
		System.out.println(obj.getClass().getName()+":The "+name+" method has a exception:"+e.getMessage());
	}
	return result;
}
  1. 测试类Test中mul方法传参为1,1时执行结果:

    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 result of the mul method is 1
    –>1

    可见与上述返回增强的示例输出结果相同

  2. 测试类Test中mul方法传参为0,1时执行结果:

    com.jd.calculator.CalculatorService:The mul method begins.
    com.jd.calculator.CalculatorService:Parameters of the mul method: [0,1]
    com.jd.calculator.CalculatorService:The mul method ends.
    com.jd.calculator.CalculatorService:The mul method has a exception:两数的乘积不能为0!

    可见与上述异常增强的示例输出结果相同

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值