Spring-AOP两种基本配置方式

Spring AOP

  • AspectJ:Java 社区里最完整最流行的 AOP 框架.
  • 在 Spring2.0 以上版本中, 可以使用基于 AspectJ 注解或基于 XML 配置的 AOP

在 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 创建代理.

用 AspectJ 注解声明切面

  • 要在 Spring 中声明 AspectJ 切面, 只需要在 IOC 容器中将切面声明为 Bean 实例. 当在 Spring IOC 容器中初始化 AspectJ 切面之后, Spring IOC 容器就会为那些与 AspectJ 切面相匹配的 Bean 创建代理.
  • 在 AspectJ 注解中, 切面只是一个带有 @Aspect 注解的 Java 类.
  • 通知是标注有某种注解的简单的 Java 方法.
  • AspectJ 支持 5 种类型的通知注解:
    • @Before: 前置通知, 在方法执行之前执行
    • @After: 后置通知, 在方法执行之后执行
    • @AfterRunning: 返回通知, 在方法返回结果之后执行
    • @AfterThrowing: 异常通知, 在方法抛出异常之后
    • @Around: 环绕通知, 围绕着方法执行
package com.atguigu.spring.aop;

import java.util.Arrays;

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.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
 * 可以使用 @Order 注解指定切面的优先级,数字越小优先级越高
 * @author hasee
 *
 */
@Order(2)
@Aspect
@Component
public class LoggingAspect {
	
	/**
	 * 定义一个方法,用于声明切入点表达式.一般地,该方法中再不需要添入其他的代码
	 * 使用 @Pointcut 来声明切入点表达式.
	 * 后面的其他通知直接使用方法名来引用当前的切入点表达式. 
	 * 
	 */
	@Pointcut("execution(public int com.atguigu.spring.aop.ArithmeticCalculator.*(..))")
	public void declareJointPointExpression() {}

	/**
	 * 在每一个接口的实现类的每一个方法开始之前执行一段代码
	 */
	@Before("declareJointPointExpression()")
	public void beforeMethod(JoinPoint joinPoint) {
		// TODO Auto-generated method stub
		String methodName = joinPoint.getSignature().getName();
		Object[] args = joinPoint.getArgs();
		System.out.println("The method " + methodName + "begins with " + Arrays.asList(args));
	}

	@After("declareJointPointExpression()")
	public void afterMethod(JoinPoint joinPoint) {
		String methodName = joinPoint.getSignature().getName();
		System.out.println("The method " + methodName + "ends");
	}
	/**
	 * 在方法正常结束后执行的代码
	 * 返回通知是可以访问到方法的返回值的!
	 * @param joinPoint
	 */
	@AfterReturning(value = "declareJointPointExpression()",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 = "declareJointPointExpression()",throwing="ex")
	public void afterReturning(JoinPoint joinPoint,  Exception ex) {
		String methodName = joinPoint.getSignature().getName();
		System.out.println("The method " + methodName + "occurs excetion :" + ex);
	}
	
	/**
	 * 环绕通知需要携带 PriceedingJoinPoint 类型的参数.
	 * 环绕通知类似于动态代理的全过程: ProceedingJoinPoint 类型的参数可以决定是否执行目标方法.
	 * 且环绕通知必须有给返回值,返回值即为目标方法的返回值 
	 * @param pjd
	 */
	@Around("declareJointPointExpression()")
	public Object aroundMethod(ProceedingJoinPoint pjd) {
		
		Object result = null;
		String methodName = pjd.getSignature().getName();
		
		//执行目标方法
//		System.out.println("aroundMethod");
		try {
			//前置通知
			System.out.println("The method " + methodName + "begins with " + Arrays.asList(pjd.getArgs()));
			result = pjd.proceed();
			
		} catch (Throwable e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return result;
		}
}

用基于 XML 的配置声明切面

  • 除了使用 AspectJ 注解声明切面, Spring 也支持在 Bean 配置文件中声明切面. 这种声明是通过 aop schema 中的 XML 元素完成的.
  • 正常情况下, 基于注解的声明要优先于基于 XML 的声明. 通过 AspectJ 注解, 切面可以与 AspectJ 兼容, 而基于 XML 的配置则是 Spring 专有的. 由于 AspectJ 得到越来越多的 AOP 框架支持, 所以以注解风格编写的切面将会有更多重用的机会.
<?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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">

	<!-- 配置 bean -->
	<bean id="arithmeticCalculator"
		class="com.atguigu.spring.aop.xml.ArithmeticCalculatorImpl"></bean>
	<!-- 配置切面的 bean -->
	<bean id="loggingAspect"
		class="com.atguigu.spring.aop.xml.LoggingAspect"></bean>

	<bean id="vlidationAspect"
		class="com.atguigu.spring.aop.xml.VlidationAspect"></bean>

	<!-- 配置 AOP -->
	<aop:config>
		<!-- 配置切点表达式 -->
		<aop:pointcut
			expression="execution(* com.atguigu.spring.aop.xml.ArithmeticCalculator.*(int,int))"
			id="pointcut" />
		<!-- 配置切面及通知 -->
		<aop:aspect ref="loggingAspect" order="2">
			<aop:before method="beforeMethod" pointcut-ref="pointcut" />
			<aop:after method="afterMethod" pointcut-ref="pointcut"/>
			<aop:after-returning method="afterReturning" pointcut-ref="pointcut" returning="result"/>
			<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="ex"/>
		</aop:aspect>
	</aop:config>

</beans>

猜你喜欢

转载自blog.csdn.net/weixin_37590761/article/details/86567867
今日推荐