一、目标
继续完成后置通知的另一个分支,异常返回后置通知
二、实现
新建一个异常返回通知接口
- 定义一个异常抛出后执行的方法,用于在目标方法抛出异常时执行自定义逻辑
public interface AfterThrowingAdvice extends Advice {
/**
* 在目标方法抛出异常时调用。
*
* @param method 目标方法
* @param args 方法参数
* @param target 目标对象
* @param ex 抛出的异常
* @throws Throwable 如果执行过程中发生异常
*/
void afterThrowing(Method method, Object[] args, Object target, Throwable ex) throws Throwable;
}
新建一个异常返回通知拦截器AfterThrowingAdviceInterceptor
- 将
AfterThrowingAdvice
包装为MethodInterceptor
public class AfterThrowingAdviceInterceptor implements MethodInterceptor {
// 异常返回通知
private AfterThrowingAdvice advice;
public AfterThrowingAdviceInterceptor() {
}
/**
* 构造函数。
*
* @param advice 异常返回通知
*/
public AfterThrowingAdviceInterceptor(AfterThrowingAdvice advice) {
this.advice = advice;
}
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
try {
// 执行目标方法
return invocation.proceed();
} catch (Throwable ex) {
// 调用异常返回通知的 afterThrowing 方法
this.advice.afterThrowing(invocation.getMethod(), invocation.getArguments(), invocation.getThis(), ex);
// 重新抛出异常
throw ex;
}
}
}
三、测试
新建一个异常返回通知实现类
public class LogAfterThrowingAdvice implements AfterThrowingAdvice {
@Override
public void afterThrowing(Method method, Object[] args, Object target, Throwable ex) throws Throwable {
// 异常处理逻辑:记录异常信息
System.out.println("After Throwing Advice: Method " + method.getName() + " threw an exception.");
System.out.println("Exception message: " + ex.getMessage());
}
}
修改spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<!-- 注册 Husband Bean -->
<bean id="husband" class="cn.shopifymall.springframework.test.bean.Husband">
<property name="wife" ref="wife"/>
</bean>
<!-- 注册 Wife Bean -->
<bean id="wife" class="cn.shopifymall.springframework.test.bean.Wife">
<property name="husband" ref="husband"/>
</bean>
<!-- 配置自动代理创建器 -->
<bean class="cn.shopifymall.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
<!-- 配置 PropertyPlaceholderConfigurer -->
<bean class="cn.shopifymall.springframework.beans.factory.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:application.properties"/>
</bean>
<!-- 异常返回通知 -->
<bean id="afterThrowingAdvice" class="cn.shopifymall.springframework.test.bean.LogAfterThrowingAdvice"/>
<!-- 异常返回通知的拦截器 -->
<bean id="afterThrowingInterceptor" class="cn.shopifymall.springframework.aop.framework.adapter.AfterThrowingAdviceInterceptor">
<property name="advice" ref="afterThrowingAdvice"/>
</bean>
<!-- 异常返回通知的切面通知器 -->
<bean id="afterThrowingAdvisor" class="cn.shopifymall.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor">
<property name="expression" value="execution(* cn.shopifymall.springframework.test.bean.Housework.doHousework(..))"/>
<property name="advice" ref="afterThrowingInterceptor"/>
</bean>
</beans>
测试类
@Test
public void test_exception_advice() {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");
// 获取 Husband 对象
Husband husband = (Husband) applicationContext.getBean("husband");
// 调用 doHousework 方法,验证拦截器是否生效
husband.doHousework();
}
主动抛出异常
@Data
public class Husband implements Housework {
@Autowired
private Wife wife;
@Override
public String doHousework() {
System.out.println("老公正在做家务");
// 模拟抛出异常
throw new RuntimeException("Housework failed!");
}
@Override
public String toString() {
return "Husband";
}
}
效果
- 执行了异常通知的代码后,再次将异常抛
老公正在做家务
After Throwing Advice: Method doHousework threw an exception.
Exception message: Housework failed!
Disconnected from the target VM, address: '127.0.0.1:9958', transport: 'socket'
java.lang.RuntimeException: Housework failed!
at cn.shopifymall.springframework.test.bean.Husband.doHousework(Husband.java:22)
......