1、获取拦截方法的返回值和抛的异常信息

获取方法返回的值分为两个步骤:

1、在返回值通知的方法中,追加一个参数 Object result
2、然后在@AfterReturning注解中添加参数returning=“参数名”

获取方法抛出的异常分为两个步骤:

1、在异常通知的方法中,追加一个参数Exception exception
2、然后在@AfterThrowing 注解中添加参数 throwing=“参数名”

修改LogUtil切面类的代码

@AfterReturning(value = "execution(public int com.atguigu.aop.Calculator.add(int, int))"
			+ " || " + "execution(public * com.atguigu.aop.Calculator.d*(..))", returning = "result")
	public static void logAfterReturn(JoinPoint joinPoint, Object result) {
		System.out.println("返回之后: 日记 :【" + joinPoint.getSignature().getName() + "】 方法调用 。参数是:"
				+ Arrays.asList(joinPoint.getArgs()) + ",返回值:" + result);
	}

	@AfterThrowing(value = "execution(public int com.atguigu.aop.Calculator.add(int, int))"
			+ " || " + "execution(public * com.atguigu.aop.Calculator.d*(..))", throwing = "exception")
	public static void logThrowException(JoinPoint joinPoint, Exception exception) {
		System.out.println("抛异常:日记 :【" + joinPoint.getSignature().getName() + "】 方法调用 。参数是:"
				+ Arrays.asList(joinPoint.getArgs()) + ",异常对象:" + exception);
	}

测试结果

spring aop修改返回值 spring aop获取返回值_java

2、Spring的环绕通知

1、环绕通知使用@Around注解。
2、环绕通知如果和其他通知同时执行。环绕通知会优先于其他通知之前执行。
3、环绕通知一定要有返回值(环绕如果没有返回值。后面的其他通知就无法接收到目标方法执行的结果)。
4、在环绕通知中。如果拦截异常。一定要往外抛。否则其他的异常通知是无法捕获到异常的。

在LogUtil切面类中添加环绕通知

@Around(value = "execution(* *(..))")
	public static Object logAround(ProceedingJoinPoint proceedingJoinPoint) {
		//获取请求参数
		Object[] args = proceedingJoinPoint.getArgs();
		Object resultObject = null;
		try {
			System.out.println("环绕前置");
			//调用目标方法
			resultObject = proceedingJoinPoint.proceed(args);
			System.out.println("环绕后置");
		} catch (Throwable e) {
			System.out.println("环绕异常:" + e);
			throw new RuntimeException(e);
		} finally {
			System.out.println("环绕返回后");
		}
		//返回返回值
		return resultObject;
	}

修改测试的代码

@ContextConfiguration(locations = "classpath:applicationContext.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringAopTest {
	@Autowired
	private Calculator calculator;

	@Test
	public void test1() {
		//加法
		calculator.add(1, 2);
	}
}

执行结果

spring aop修改返回值 spring aop获取返回值_mybatis_02

3、切入点表达式的重用

切入点表达式的重点,需要分三个步骤:

1、在切面类中定义一个空的方法

public static void pointcut1() {}

2、在方法中使用@Pointcut定义一个切入连表达式

@Pointcut(value="execution(public int com.atguigu.aop.Calculator.add(int, int))" + " || "
			+ "execution(public * com.atguigu.aop.Calculator.*(..))")
	public static void pointcut1() {}

3、其他的通知注解中使用方法名()的形式引用方法上定义的切入点表达式。
比如:@Before("pointcut1()")

4、多个通知的执行顺序

当有多个切面,多个通知的时候:

1、通知的执行顺序默认是由切面类的字母先后顺序决定。
2、在切面类上使用@Order注解决定通知执行的顺序(值越小,越先执行)

再添加另一个切面类

@Component
@Aspect
@Order(1)
public class Validation {

	@Before(value = "com.atguigu.aop.LogUtil.pointcut1()")
	public static void before(JoinPoint joinPoint) {
		System.out.println("这是Validation的前置通知,拦截的方法是:" + joinPoint.getSignature().getName());
	}

	@After(value = "com.atguigu.aop.LogUtil.pointcut1()")
	public static void after(JoinPoint joinPoint) {
		System.out.println("这是Validation的后置通知,拦截的方法是:" + joinPoint.getSignature().getName());
	}

	@AfterReturning(value = "com.atguigu.aop.LogUtil.pointcut1()", returning = "result")
	public static void afterReturning(JoinPoint joinPoint, Object result) {
		System.out.println("这是Validation的后置通知,拦截的方法是:" + joinPoint.getSignature().getName()
				+ ", 返回值:" + result);
	}

}

修改原来LogUtil中的切面内容(去掉环绕通知,留下前置,后置,返回后通知)

@Aspect
@Component
@Order(2)
public class LogUtil {
	@Pointcut(value="execution(public int com.atguigu.aop.Calculator.add(int, int))" + " || "
			+ "execution(public * com.atguigu.aop.Calculator.*(..))")
	public static void pointcut1() {}

测试的代码

@ContextConfiguration(locations = "classpath:applicationContext.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringAopTest {
	@Autowired
	private Calculator calculator;
	@Test
	public void test1() {
		//加法
		calculator.add(1, 0);
	}
}

运行的结果

spring aop修改返回值 spring aop获取返回值_mybatis_03

5、如何基于xml配置aop程序

需要导入的包

com.springsource.net.sf.cglib-2.2.0.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
commons-logging-1.1.3.jar
log4j-1.2.17.jar
spring-aop-4.0.0.RELEASE.jar
spring-aspects-4.0.0.RELEASE.jar
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar
spring-expression-4.0.0.RELEASE.jar
spring-test-4.0.0.RELEASE.jar

工程中编写的类

public class Calculator {
	public int div(int num1, int num2) {
		return num1 / num2;
	}

	public int add(int num1, int num2) {
		return num1 + num2;
	}
}

LogUtil切面类

public class LogUtil {
	public static void logBefore(JoinPoint joinPoint) {
		System.out.println("前置 日记 :【" + joinPoint.getSignature().getName() + "】 方法调用前 。参数是:"
				+ Arrays.asList(joinPoint.getArgs()));
	}

	public static void logAfter(JoinPoint joinPoint) {
		System.out.println("后置 日记 :【" + joinPoint.getSignature().getName() + "】 方法调用 。参数是:"
				+ Arrays.asList(joinPoint.getArgs()));
	}

	public static void logAfterReturn(JoinPoint joinPoint, Object result) {
		System.out.println("返回之后: 日记 :【" + joinPoint.getSignature().getName() + "】 方法调用 。参数是:"
				+ Arrays.asList(joinPoint.getArgs()) + ",返回值:" + result);
	}

	public static void logThrowException(JoinPoint joinPoint, Exception exception) {
		System.out.println("抛异常:日记 :【" + joinPoint.getSignature().getName() + "】 方法调用 。参数是:"
				+ Arrays.asList(joinPoint.getArgs()) + ",异常对象:" + exception);
	}
}

Validation切面类

public class Validation {
	public static void before(JoinPoint joinPoint) {
		System.out.println("这是Validation的前置通知,拦截的方法是:" + joinPoint.getSignature().getName());
	}

	public static void after(JoinPoint joinPoint) {
		System.out.println("这是Validation的后置通知,拦截的方法是:" + joinPoint.getSignature().getName());
	}

	public static void afterReturning(JoinPoint joinPoint, Object result) {
		System.out.println("这是Validation的后置通知,拦截的方法是:" + joinPoint.getSignature().getName()
				+ ", 返回值:" + result);
	}
}

ApplicationContext.xml配置文件中的内容

<!-- 注册bean对象
		添加@Component
	 -->
	<bean id="calculator" class="com.atguigu.aop.Calculator" />
	<bean id="logUtil" class="com.atguigu.aop.LogUtil" />
	<bean id="validation" class="com.atguigu.aop.Validation" />
	<!-- 配置AOP -->
	<aop:config>
		<!-- 定义可以共用的切入点 -->
		<aop:pointcut expression="execution(* com.atguigu.aop.Calculator.*(..))" id="pointcut1"/>
		<!-- 定义切面类 -->
		<aop:aspect order="1" ref="logUtil">
			<!-- 这是前置通知 
					method属性配置通知的方法
					pointcut配置切入点表达式
			 -->
			<aop:before method="logBefore" pointcut="execution(* com.atguigu.aop.Calculator.*(..))"/>
			<aop:after method="logAfter" pointcut="execution(* com.atguigu.aop.Calculator.*(..))"/>
			<aop:after-returning method="logAfterReturn" 
				returning="result" pointcut="execution(* com.atguigu.aop.Calculator.*(..))"/>
			<aop:after-throwing method="logThrowException" throwing="exception"
				pointcut="execution(* com.atguigu.aop.Calculator.*(..))"/>
		</aop:aspect>
		<!-- 定义切面类 -->
		<aop:aspect order="2" ref="validation">
			<aop:before method="before" pointcut-ref="pointcut1"/>
			<aop:after method="after" pointcut-ref="pointcut1"/>
			<aop:after-returning method="afterReturning" 
				returning="result" pointcut-ref="pointcut1"/>
		</aop:aspect>
	</aop:config>

测试的代码

@ContextConfiguration(locations = "classpath:applicationContext.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringAopTest {
	@Autowired
	Calculator calculator;
	@Test
	public void test1() {
		calculator.add(1, 2);
	}
}

测试运行的结果

spring aop修改返回值 spring aop获取返回值_spring aop修改返回值_04