晋南讲堂之Spring—(十三)AOP

本文详细介绍了如何在Spring中启用AspectJ注解支持和XML配置文件来实现AOP。内容包括引入AspectJ相关库、配置aop:aspectj-autoproxy、创建切面、定义通知类型(Before、After、AfterReturning、AfterThrowing、Around),以及切面的优先级和切点表达式的重用。此外,还提到了不同版本AspectJ库对切点表达式的影响,以及XML配置AOP的步骤。
摘要由CSDN通过智能技术生成

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

在 Spring 中启用 AspectJ 注解支持
  1. 要在 Spring 应用中使用 AspectJ 注解, 必须在 classpath 下包含 AspectJ 类库: aopalliance.jar、aspectj.weaver.jar 和 spring-aspects.jar
  2. 将 aop Schema 添加到 根元素中.
  3. 要在 Spring IOC 容器中启用 AspectJ 注解支持, 只要在 Bean 配置文件中定义一个空的 XML 元素 aop:aspectj-autoproxy
  4. 当 Spring IOC 容器侦测到 Bean 配置文件中的 aop:aspectj-autoproxy 元素时, 会自动为与 AspectJ 切面匹配的 Bean 创建代理.

  创建新项目Spring-2:
在这里插入图片描述
在lib目录中加入如图所示的jar包,spring-aop-4.0.0.RELEASE、spring-aspects-4.0.0.RELEASE、spring-beans-4.0.0.RELEASE、spring-context-4.0.0.RELEASE、spring-core-4.0.0.RELEASE、spring-expression-4.0.0.RELEASE,这6个jar包在下载的Spring-framework的libs目录下都有,而且这些jar包必须保证版本一致(从下载的一个spring版本中一次找全),否则报错。com.springsource.org.aopalliance-1.0.0.jar、com.springsource.org.aspectj.weaver-1.6.4.RELEASE.jar、commons-logging-1.2.jar,这三个jar包自行在网上找。找齐后添加至路径。
  新建com.spring.aop.impl包,
ArithmeticCaculator.java接口:

package com.spring.aop.impl;

public interface ArithmeticCaculator {
	int add(int i,int j);
	int sub(int i,int j);
	int multiply(int i,int j);
	double div(int i,int j);

}

ArithmeticCaculatorImpl.java是上述接口的实现类,并添加Component注解:

package com.spring.aop.impl;
import org.springframework.stereotype.Component;
@Component
public class ArithmeticCaculatorImpl implements ArithmeticCaculator {
	@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 multiply(int i, int j) {
		int result=i*j;
		return result;
	}
	@Override
	public double div(int i, int j) {
		int result=i/j;
		return result;
	}
}

新建切面LoggingAspect.java:

package com.spring.aop.impl;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

//把这个类声明为一个切面:需要把该类放入IOC容器中、并声明为一个切面
@Aspect
@Component
public class LoggingAspect {
	//声明该方法是一个前置通知:在目标方法开始之前执行
	@Before("execution(public int com.spring.aop.impl.ArithmeticCaculator.add(int, int))")
	public void beforeMethod(){
		System.out.println("the Method begins");
	}
}

新建Spring配置文件applicationContext.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.2.xsd">
	<!-- 配置自动扫描的包 -->
	<context:component-scan base-package="com.spring.aop.impl"></context:component-scan>
	<!-- 使AspectJ注解起作用:自动为匹配的类生成代理对象 -->
	<aop:aspectj-autoproxy ></aop:aspectj-autoproxy>
	
</beans>

新建Main.java:

package com.spring.aop.impl;

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的实例
		ArithmeticCaculator arithmeticCaculator = ctx.getBean(ArithmeticCaculator.class);//通过类型来获取bean
		//3.使用Bean
		int result = arithmeticCaculator.add(4, 5);
		System.out.println("result:"+result);

	}

}

运行主函数:
在这里插入图片描述
也可以将LoggingAspect.java改成这样:

package com.spring.aop.impl;

import java.util.Arrays;
import java.util.List;

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

//把这个类声明为一个切面:需要把该类放入IOC容器中、并声明为一个切面
@Aspect
@Component
public class LoggingAspect {
	//声明该方法是一个前置通知:在目标方法开始之前执行
	@Before("execution(public int com.spring.aop.impl.ArithmeticCaculator.add(int, int))")
	public void beforeMethod(JoinPoint joinpoint){//注意是JoinPoint类而不是Joinpoint类
		String methodName=joinpoint.getSignature().getName();//获取函数名
		List<Object> args=Arrays.asList(joinpoint.getArgs());//获取函数的实参
		System.out.println("the Method "+methodName+" begins with"+args);
	}
}

输出:
在这里插入图片描述
在主函数中添加减法:
在这里插入图片描述
同时将切面中的before注解中add方法改为*,如下:
在这里插入图片描述
则可以实现给 public int型、形参为(int,int)的方法自动添加前置通知:
在这里插入图片描述
如果是div方法,则不能实现,因为返回时double类型的。

通知是标注有某种注解的简单的 Java 方法.
AspectJ 支持 5 种类型的通知注解:
@Before: 前置通知, 在方法执行之前执行
@After: 后置通知, 在方法执行之后执行
@AfterRunning: 返回通知, 在方法返回结果之后执行
@AfterThrowing: 异常通知, 在方法抛出异常之后
@Around: 环绕通知, 围绕着方法执行

最典型的切入点表达式时根据方法的签名来匹配各种方法:

execution * com.atguigu.spring.ArithmeticCalculator.*(..):表示 匹配 ArithmeticCalculator 中声明的所有方法,第一个 * 代表任意修饰符及任意返回值. 第二个 * 代表任意方法. .. 匹配任意数量的参数. 若目标类与接口与该切面在同一个包中, 可以省略包名.
execution public * ArithmeticCalculator.*(..)::匹配 ArithmeticCalculator 接口的所有公有方法.
execution public double ArithmeticCalculator.*(..): 匹配 ArithmeticCalculator 中返回 double 类型数值的方法
execution public double ArithmeticCalculator.*(double, ..): 匹配第一个参数为 double 类型的方法, .. 匹配任意数量任意类型的参数
execution public double ArithmeticCalculator.*(double, double):匹配参数类型为 double, double 类型的方法.

在这里插入图片描述

  在LoggingAspect.java切面中增加如下后置通知,后置通知无论方法是否返回异常都会输出:

package com.spring.aop.impl;

import java.util.Arrays;
import java.util.List;

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

//把这个类声明为一个切面:需要把该类放入IOC容器中、并声明为一个切面
@Aspect
@Component
public class LoggingAspect {
	//声明该方法是一个前置通知:在目标方法开始之前执行
	@Before("execution(public int com.spring.aop.impl.ArithmeticCaculator.*(..))")
	public void beforeMethod(JoinPoint joinpoint){//注意是JoinPoint类而不是Joinpoint类
		String methodName=joinpoint.getSignature().getName();//获取函数名
		List<Object> args=Arrays.asList(joinpoint.getArgs());//获取函数的实参
		System.out.println("the Method "+methodName+" begins with"+args);
	}
	
	//后置通知:在目标方法执行后(无论是否发生异常),执行的通知
	//在后置通知中还不能访问目标方法执行的结果
	@After("execution(* com.spring.aop.impl.*.*(..))")
	public void afterMethod(JoinPoint joinPoint){
		String methodName=joinPoint.getSignature().getName();//获取函数名
		List<Object> args=Arrays.asList(joinPoint.getArgs());//获取函数的实参
		System.out.println("the Method "+methodName+" ends with"+args);
	}
}

运行后结果:
在这里插入图片描述
  下面在LoggingAspect.java增加返回通知:

/**
	 * 在方法正常结束后执行的代码
	 * 返回通知可以访问到方法的返回值
	 */
	@AfterReturning(value="execution(* com.spring.aop.impl.*.*(..))"
			,returning="result")
	public void returnMethod(JoinPoint joinPoint,Object result){
		String methodName=joinPoint.getSignature().getName();//获取函数名
		System.out.println("the Method "+methodName+" ends with "+result);
	}

如果方法抛出异常是不显示返回通知的。
  在切面中增加异常通知,异常通知只有在方法出现异常时才执行:

/**
	 * 在目标方法出现异常时会执行的代码
	 * 可以访问到异常对象;且可以指定在出现特定异常时再执行代码
	 */
	@AfterThrowing(value="execution(* com.spring.aop.impl.*.*(..))"
			,throwing="e")
	public void afterThrowing(JoinPoint joinPoint,Exception e){
		String methodName=joinPoint.getSignature().getName();//获取函数名
		System.out.println("the Method "+methodName+" occurs exception: "+e);
	}

得到结果:
在这里插入图片描述
  环绕通知:

/**
	 * 环绕通知需要携带ProceedingJoinPoint类型的参数
	 * 环绕通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行目标方法
	 * 且环绕通知必须有返回值,返回值即为目标方法的返回值
	 */
	@Around("execution(* com.spring.aop.impl.*.*(..))")
	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 + " ends with " + result);
		} catch (Throwable e) {
			//异常通知
			System.out.println("The method " + methodName + " occurs exception:" + e);
			throw new RuntimeException(e);
		}
		//后置通知
		System.out.println("The method " + methodName + " ends");
		
		return result;
	}

返回结果:
在这里插入图片描述

切面的优先级

  在com.spring.aop.impl包中新建另一个认证参数的切面ValidateAspect.java:
在这里插入图片描述
这时候存在两个切面,这两个切面,这两个切面谁先执行,可以通过@Order注解来规定。
ValidateAspect.java:

package com.spring.aop.impl;

import java.util.Arrays;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Order(1)
@Aspect
@Component
public class ValidateAspect {
	@Before("execution(* com.spring.aop.impl.*.*(..))")
	public void validateArgs(JoinPoint joinPoint){
		System.out.println("-->validate"+Arrays.asList(joinPoint.getArgs()));
	}

}

LoggingAspect.java:

package com.spring.aop.impl;

import java.util.Arrays;
import java.util.List;

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.core.annotation.Order;
import org.springframework.stereotype.Component;

//把这个类声明为一个切面:需要把该类放入IOC容器中、并声明为一个切面
@Order(2)
@Aspect
@Component
public class LoggingAspect {
	//声明该方法是一个前置通知:在目标方法开始之前执行
	/*@Before("execution(public int com.spring.aop.impl.ArithmeticCaculator.*(..))")
	public void beforeMethod(JoinPoint joinpoint){//注意是JoinPoint类而不是Joinpoint类
		String methodName=joinpoint.getSignature().getName();//获取函数名
		List<Object> args=Arrays.asList(joinpoint.getArgs());//获取函数的实参
		System.out.println("the Method "+methodName+" begins with"+args);
	}*/
	
	//后置通知:在目标方法执行后(无论是否发生异常),执行的通知
	//在后置通知中还不能访问目标方法执行的结果
	/*@After("execution(* com.spring.aop.impl.*.*(..))")
	public void afterMethod(JoinPoint joinPoint){
		String methodName=joinPoint.getSignature().getName();//获取函数名
		List<Object> args=Arrays.asList(joinPoint.getArgs());//获取函数的实参
		System.out.println("the Method "+methodName+" ends with"+args);
	}
	*//**
	 * 在方法正常结束后执行的代码
	 * 返回通知可以访问到方法的返回值
	 *//*
	@AfterReturning(value="execution(* com.spring.aop.impl.*.*(..))"
			,returning="result")
	public void returnMethod(JoinPoint joinPoint,Object result){
		String methodName=joinPoint.getSignature().getName();//获取函数名
		System.out.println("the Method "+methodName+" ends with "+result);
	}
	
	*//**
	 * 在目标方法出现异常时会执行的代码
	 * 可以访问到异常对象;且可以指定在出现特定异常时再执行代码
	 *//*
	@AfterThrowing(value="execution(* com.spring.aop.impl.*.*(..))"
			,throwing="e")
	public void afterThrowing(JoinPoint joinPoint,Exception e){
		String methodName=joinPoint.getSignature().getName();//获取函数名
		System.out.println("the Method "+methodName+" occurs exception: "+e);
	}*/
	/**
	 * 环绕通知需要携带ProceedingJoinPoint类型的参数
	 * 环绕通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行目标方法
	 * 且环绕通知必须有返回值,返回值即为目标方法的返回值
	 */
	@Around("execution(* com.spring.aop.impl.*.*(..))")
	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 + " ends with " + result);
		} catch (Throwable e) {
			//异常通知
			System.out.println("The method " + methodName + " occurs exception:" + e);
			throw new RuntimeException(e);
		}
		//后置通知
		System.out.println("The method " + methodName + " ends");
		
		return result;
	}
	
}

@Order中的值越小,优先级越高:
在这里插入图片描述

重用切点表达式

  在下述切面中,注解中的切点表达式都是相同的,如下,能否重用呢?

execution(* com.spring.aop.impl.*.*(..))
package com.spring.aop.impl;

import java.util.Arrays;
import java.util.List;

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.core.annotation.Order;
import org.springframework.stereotype.Component;

//把这个类声明为一个切面:需要把该类放入IOC容器中、并声明为一个切面
@Order(2)
@Aspect
@Component
public class LoggingAspect {
	//声明该方法是一个前置通知:在目标方法开始之前执行
	@Before("execution(* com.spring.aop.impl.*.*(..))")
	public void beforeMethod(JoinPoint joinpoint){//注意是JoinPoint类而不是Joinpoint类
		String methodName=joinpoint.getSignature().getName();//获取函数名
		List<Object> args=Arrays.asList(joinpoint.getArgs());//获取函数的实参
		System.out.println("the Method "+methodName+" begins with"+args);
	}
	
	//后置通知:在目标方法执行后(无论是否发生异常),执行的通知
	//在后置通知中还不能访问目标方法执行的结果
	@After("execution(* com.spring.aop.impl.*.*(..))")
	public void afterMethod(JoinPoint joinPoint){
		String methodName=joinPoint.getSignature().getName();//获取函数名
		List<Object> args=Arrays.asList(joinPoint.getArgs());//获取函数的实参
		System.out.println("the Method "+methodName+" ends with"+args);
	}
	/**
	 * 在方法正常结束后执行的代码
	 * 返回通知可以访问到方法的返回值
	 */
	@AfterReturning(value="execution(* com.spring.aop.impl.*.*(..))"
			,returning="result")
	public void returnMethod(JoinPoint joinPoint,Object result){
		String methodName=joinPoint.getSignature().getName();//获取函数名
		System.out.println("the Method "+methodName+" ends with "+result);
	}
	
	/**
	 * 在目标方法出现异常时会执行的代码
	 * 可以访问到异常对象;且可以指定在出现特定异常时再执行代码
	 */
	@AfterThrowing(value="execution(* com.spring.aop.impl.*.*(..))"
			,throwing="e")
	public void afterThrowing(JoinPoint joinPoint,Exception e){
		String methodName=joinPoint.getSignature().getName();//获取函数名
		System.out.println("the Method "+methodName+" occurs exception: "+e);
	}
	
}

可以在切面中定义一个没有方法体的空的方法,使用@Pointcut注解来表示:

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

这样,其他通知就可以变为如下:

package com.spring.aop.impl;

import java.util.Arrays;
import java.util.List;

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;

//把这个类声明为一个切面:需要把该类放入IOC容器中、并声明为一个切面
@Order(2)
@Aspect
@Component
public class LoggingAspect {
	/**
	 * 定义一个方法,用于声明切入点表达式。一般的,该方法不需要添加其他代码。
	 */
	@Pointcut("execution(* com.spring.aop.impl.*.*(..))")
	public void declarJoinPointExpression(){}
	//声明该方法是一个前置通知:在目标方法开始之前执行
	@Before("declarJoinPointExpression()")
	public void beforeMethod(JoinPoint joinpoint){//注意是JoinPoint类而不是Joinpoint类
		String methodName=joinpoint.getSignature().getName();//获取函数名
		List<Object> args=Arrays.asList(joinpoint.getArgs());//获取函数的实参
		System.out.println("the Method "+methodName+" begins with"+args);
	}
	
	//后置通知:在目标方法执行后(无论是否发生异常),执行的通知
	//在后置通知中还不能访问目标方法执行的结果
	@After("declarJoinPointExpression()")
	public void afterMethod(JoinPoint joinPoint){
		String methodName=joinPoint.getSignature().getName();//获取函数名
		List<Object> args=Arrays.asList(joinPoint.getArgs());//获取函数的实参
		System.out.println("the Method "+methodName+" ends with"+args);
	}
	/**
	 * 在方法正常结束后执行的代码
	 * 返回通知可以访问到方法的返回值
	 */
	@AfterReturning(value="declarJoinPointExpression()"
			,returning="result")
	public void returnMethod(JoinPoint joinPoint,Object result){
		String methodName=joinPoint.getSignature().getName();//获取函数名
		System.out.println("the Method "+methodName+" ends with "+result);
	}
	
	/**
	 * 在目标方法出现异常时会执行的代码
	 * 可以访问到异常对象;且可以指定在出现特定异常时再执行代码
	 */
	@AfterThrowing(value="declarJoinPointExpression()"
			,throwing="e")
	public void afterThrowing(JoinPoint joinPoint,Exception e){
		String methodName=joinPoint.getSignature().getName();//获取函数名
		System.out.println("the Method "+methodName+" occurs exception: "+e);
	}
	
}

在同一个包的其他切面,可以采用“类名.方法”的形式,如下:

package com.spring.aop.impl;

import java.util.Arrays;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Order(1)
@Aspect
@Component
public class ValidateAspect {
	@Before("LoggingAspect.declarJoinPointExpression()")
	public void validateArgs(JoinPoint joinPoint){
		System.out.println("-->validate"+Arrays.asList(joinPoint.getArgs()));
	}

}

如果在不同包,则需要前面加包名,即“包名.类名.方法名”。注意,在使用该方式时,使用的是com.springsource.org.aspectj.weaver-1.6.4.RELEASE.jar即1.6.4版本的,这个会报出如下错误:
在这里插入图片描述
原因是jar包的版本太低了,将其置换为com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar即1.6.8版本就可以了。可正常输出结果:
在这里插入图片描述

在 Spring 中启用XML配置文件的方式配置AOP

将com.spring.aop.impl包复制到com.spring.aop.impl.xml,删除其中所有的注解:
在这里插入图片描述

package com.spring.aop.impl.xml;

public interface ArithmeticCaculator {
	int add(int i,int j);
	int sub(int i,int j);
	int multiply(int i,int j);
	double div(int i,int j);

}

package com.spring.aop.impl.xml;

public class ArithmeticCaculatorImpl implements ArithmeticCaculator {
	@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 multiply(int i, int j) {
		int result=i*j;
		return result;
	}
	@Override
	public double div(int i, int j) {
		int result=i/j;
		return result;
	}
}

package com.spring.aop.impl.xml;

import java.util.Arrays;
import java.util.List;

import org.aspectj.lang.JoinPoint;

public class LoggingAspect {

	public void beforeMethod(JoinPoint joinpoint){//注意是JoinPoint类而不是Joinpoint类
		String methodName=joinpoint.getSignature().getName();//获取函数名
		List<Object> args=Arrays.asList(joinpoint.getArgs());//获取函数的实参
		System.out.println("the Method "+methodName+" begins with"+args);
	}

	public void afterMethod(JoinPoint joinPoint){
		String methodName=joinPoint.getSignature().getName();//获取函数名
		List<Object> args=Arrays.asList(joinPoint.getArgs());//获取函数的实参
		System.out.println("the Method "+methodName+" ends with"+args);
	}

	public void returnMethod(JoinPoint joinPoint,Object result){
		String methodName=joinPoint.getSignature().getName();//获取函数名
		System.out.println("the Method "+methodName+" ends with "+result);
	}

	public void afterThrowing(JoinPoint joinPoint,Exception e){
		String methodName=joinPoint.getSignature().getName();//获取函数名
		System.out.println("the Method "+methodName+" occurs exception: "+e);
	}
	
}

package com.spring.aop.impl.xml;

import java.util.Arrays;

import org.aspectj.lang.JoinPoint;

public class ValidateAspect {
	
	public void validateArgs(JoinPoint joinPoint){
		System.out.println("-->validate"+Arrays.asList(joinPoint.getArgs()));
	}

}

在src下新建applicationContext_xml.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"
	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只是给class中的类起了个别名,用于在主函数中根据该id来获取这个类型的bean -->
	<bean id="arithmeticCaculator" class="com.spring.aop.impl.xml.ArithmeticCaculatorImpl"></bean>
	<!-- 配置切面 --><!--id为了配置AOP时引用这两个bean  -->
	<bean id="LoggingAspect" class="com.spring.aop.impl.xml.LoggingAspect"></bean>
	<bean id="ValidateAspect" class="com.spring.aop.impl.xml.ValidateAspect"></bean>
	<!-- 配置AOP -->
	<aop:config>
		<!-- 配置切点表达式 --><!--  -->
		<aop:pointcut expression="execution(* com.spring.aop.impl.xml.ArithmeticCaculator.*(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-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="e"/>
			<aop:after-returning method="returnMethod" pointcut-ref="pointcut" returning="result"/>
		</aop:aspect>
		<aop:aspect ref="ValidateAspect" order="1">
			<aop:before method="validateArgs" pointcut-ref="pointcut"/>
		</aop:aspect>
		
	</aop:config>

</beans>

首先需要将类配置成bean,然后配置AOP,需要配置切点表达式,然后配置切面和通知。运行主函数后得到如下结果:
在这里插入图片描述
发生异常时返回异常通知:
在这里插入图片描述
注意在写配置文件时,有预定义好的标签,这时千万不去手打,而是按住“Alt+/”来调出标签列表

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值