Spring AOP中 前置、后置、返回、异常、环绕通知的实例

1 在Spring中启用AspectJ注解支持
  要在Spring应用中使用AspectJ注解,必须在classpath下包含AspectJ类库:aopalliance.jar、aspectj.weaver.jar和spring-aspects.jar
  将aop Schema添加到<beans>根元素中。
  要在Spring IOC容器中启用AspectJ注解支持,只要早bean配置文件中定义一个空的XML元素<aop:aspectj-autoproxy>
  当Spring IOC容器侦测到bean配置文件中的<aop:aspectj-autoproxy>元素时,会自动为与AspectJ切面匹配的bean创建代理
2 用AspectJ注解声明切面
  要在Spring中声明AspectJ切面,只需要在IOC容器中将切面声明为bean实例。当在Spring IOC容器中初始化AspectJ切面之后,Spring IOC容器就会为那些与AspectJ切面相匹配的bean创建代理
  在AspectJ注解中,切面只是一个带有@AspectJ注解的Java类
  通知是标注有某种注解的简单的Java方法
  AspectJ支持5种类型的通知注解:
    @Before:前置通知,在方法执行之前返回
    @After:后置通知,在方法执行后执行
    @AfterRunning:返回通知,在方法返回结果之后执行
    @AfterThrowing:异常通知,在方法抛出异常之后
    @Around:环绕通知,围绕着方法执行

下面我们来看一个实例:

ArithmeticCalculator接口:

package com.primary.spring.aop;

public interface ArithmeticCalculator {

	int add(int i, int j);
	int sub(int i, int j);
	int mul(int i, int j);
	int div(int i, int j);
}

ArithmeticCalculator的实现类 ArithmeticCalculatorImpl:

package com.primary.spring.aop;

import org.springframework.stereotype.Component;

@Component
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {

	@Override
	public int add(int i, int j) {
		int result = i + j;
		return result;
	}

	@Override
	public int sub(int i, int j) {
		int result = i - j;
		return result;
	}

	@Override
	public int mul(int i, int j) {
		int result = i * j;
		return result;
	}

	@Override
	public int div(int i, int j) {
		int result = i / j;
		return result;
	}

}

配置自动扫描的包和配置自动为匹配aspectJ 注解的java类生成代理对象的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:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop"
	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.0.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
	
	<!-- 配置自动扫描的包 -->
	<context:component-scan base-package="com.primary.spring.aop"></context:component-scan>
	
	<!-- 配置自动为匹配aspectJ 注解的java类生成代理对象 -->
	<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

@Pointcut切点表达式 :后面的其他通知直接使用方法名来引用当前切入点的表达式

/**
	 * 切入点表达式的声明,一般地,该方法中不需要再添加其他代码
	 * 使用@Pointcut来声明切入点表达式
	 * 后面的其他通知直接使用方法名来引用当前切入点的表达式
	 */
	@Pointcut("execution(* com.primary.spring.aop.*.*(..))")
	public void declareJointPointExpression() {}

@Before:前置通知,在方法执行之前返回

/**
	 *前置通知:声明该方法是一个前置通知:在目标方法开始之前执行
	 * @param joinPoint
	 */
	@Before("declareJointPointExpression()")
	public void beforeMethod(JoinPoint joinPoint) {
		
		// 在通知的方法中声明一个类型为JoinPoint的参数, 然后就可以访问链接细节,如方法和参数值。
		String methodName = joinPoint.getSignature().getName();
		List<Object> args = Arrays.asList(joinPoint.getArgs());
		System.out.println("The methed " + methodName + " begins with " + args);
	}

 @After:后置通知,在方法执行后执行

/**
	 * 后置通知:声明该方法是一个后置通知:在目标方法执行后(无论该方法是否发生异常), 一定会打印通知.
	 * 在后置通知中不能访问目标方法执行的结果
	 * @param joinPoint
	 */
	@After("declareJointPointExpression()")
	public void AfterMethod(JoinPoint joinPoint) {
		String methodName = joinPoint.getSignature().getName();
		System.out.println("The methed " + methodName + " ends");
	}

@AfterRunning:返回通知,在方法返回结果之后执行

/**
	 *返回通知:在方法正常结束后执行的代码, 返回通知是可以访问到方法的返回值的!
	 * @param joinPoint
	 * @param result
	 */
	@AfterReturning(value = "declareJointPointExpression()",
			returning="result")
	public void afterReturning(JoinPoint joinPoint, Object result) {
		String methodName = joinPoint.getSignature().getName();
		System.out.println("The methed " + methodName + " return with " + result);
	}
	

@AfterThrowing:异常通知,在方法抛出异常之后

/**
	 * 异常通知:在目标方法出现异常时会执行的代码
	 * 可以访问到异常对象,且可以指定在出现特定异常时执行通知代码
	 * @param joinPoint
	 * @param e
	 */
	@AfterThrowing(value = "declareJointPointExpression()",
			throwing="e")
	public void afterThrowing(JoinPoint joinPoint,Exception e) {
		String methodName = joinPoint.getSignature().getName();
		System.out.println("The methed " + methodName + " occurs excetion " + e);
	}

@Around:环绕通知,围绕着方法执行:环绕通知类似于动态代理全过程即综合了(前置、后置、返回、异常通知)为一体的通知:


	/**
	 * 环绕通知:需要携带ProceedingJoinPoint 类型的参数
	 * 环绕通知类似于动态代理全过程即综合了(前置、后置、返回、异常通知)为一体的通知:ProceedingJoinPoint 类型的参数可以决定是否执行目标方法
	 * 且环绕通知必须要有返回值,返回值即为目标方法的返回值
	 * @param proceedingJoinPoint
	 * @return 
	 */
	@Around("execution(* com.primary.spring.aop.*.*(..))")
	public Object aroundMethod(ProceedingJoinPoint proceedingJoinPoint) {
		
		Object result = null;
		String methodName = proceedingJoinPoint.getSignature().getName();
		//执行目标方法
		try {
			//前置通知
			System.out.println("The method " + methodName + " begins with " + Arrays.asList(proceedingJoinPoint.getArgs()));
			result = proceedingJoinPoint.proceed();
			//返回通知
			System.out.println("The method "+ methodName + " return with " + result);
		} catch (Throwable e) {
			e.printStackTrace();
			//异常通知
			System.out.println("The method "+ methodName + " occurs exception: " + e);
		}
		//后置通知
		System.out.println("The method " + methodName + " ends");
		
		return result;
	}

测试方法:

package com.primary.spring.aop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {

	public static void main(String[] args) {
		
		//1 .创建Spring的IOC容器
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

		//2. 从IOC容器中获取bean的实例
		ArithmeticCalculator arithmeticCalculator = ctx.getBean(ArithmeticCalculator.class);
		
		//3. 使用bean
		int result = arithmeticCalculator.add(3, 4);
		System.out.println("result: " + result);
		
		result = arithmeticCalculator.div(3, 1);
		System.out.println("result: " + result);
	}
}

我们发现用@Before、@After、@AfterRunning、@AfterThrowing执行的效果和单独使用@Around通知效果一样,但不等于环绕通知一定好于前面的四种通知:

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

金州饿霸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值