Java后置通知(After Advice)实现案例
后置通知(After Advice)是在目标方法执行后执行的增强,无论方法是否抛出异常都会执行,下面是几个实现案例:

基于Spring AOP的XML配置实现
1 定义目标接口和实现类
// 目标接口
public interface UserService {
void addUser(String username);
void deleteUser(int userId) throws Exception;
}
// 目标实现类
public class UserServiceImpl implements UserService {
@Override
public void addUser(String username) {
System.out.println("添加用户:" + username);
}
@Override
public void deleteUser(int userId) throws Exception {
System.out.println("删除用户,ID:" + userId);
if (userId <= 0) {
throw new Exception("用户ID无效");
}
}
}
2 定义后置通知切面类
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class LogAfterAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method,
Object[] args, Object target) throws Throwable {
System.out.println("===== 后置通知开始 =====");
System.out.println("目标类:" + target.getClass().getName());
System.out.println("方法名:" + method.getName());
System.out.println("参数:");
if (args != null) {
for (Object arg : args) {
System.out.println(" - " + arg);
}
}
System.out.println("返回值:" + returnValue);
System.out.println("===== 后置通知结束 =====");
}
}
3 Spring配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 目标对象 -->
<bean id="userServiceTarget" class="com.example.UserServiceImpl"/>
<!-- 后置通知 -->
<bean id="logAfterAdvice" class="com.example.LogAfterAdvice"/>
<!-- 创建代理 -->
<bean id="userService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="userServiceTarget"/>
<property name="interceptorNames">
<list>
<value>logAfterAdvice</value>
</list>
</property>
</bean>
</beans>
基于@AspectJ注解实现
1 切面类(使用@After注解)
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
// 后置通知 - 在方法执行后执行,无论是否抛出异常
@After("execution(* com.example.UserService.*(..))")
public void afterMethod(JoinPoint joinPoint) {
System.out.println("===== @After后置通知 =====");
System.out.println("目标方法:" + joinPoint.getSignature().getName());
System.out.println("目标类:" + joinPoint.getTarget().getClass().getSimpleName());
System.out.println("参数:" + Arrays.toString(joinPoint.getArgs()));
System.out.println("==========================");
}
// 返回通知 - 只在方法正常返回时执行
@AfterReturning(pointcut = "execution(* com.example.UserService.*(..))",
returning = "result")
public void afterReturningMethod(JoinPoint joinPoint, Object result) {
System.out.println("===== @AfterReturning返回通知 =====");
System.out.println("方法正常返回,返回值:" + result);
System.out.println("================================");
}
// 异常通知 - 只在方法抛出异常时执行
@AfterThrowing(pointcut = "execution(* com.example.UserService.*(..))",
throwing = "exception")
public void afterThrowingMethod(JoinPoint joinPoint, Exception exception) {
System.out.println("===== @AfterThrowing异常通知 =====");
System.out.println("方法抛出异常:" + exception.getMessage());
System.out.println("================================");
}
}
2 Spring配置(启用AspectJ)
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.example")
public class AppConfig {
// 其他bean配置
}
测试代码
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AfterAdviceTest {
public static void main(String[] args) {
// XML配置方式
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = context.getBean("userService", UserService.class);
// 测试正常执行
System.out.println("=== 测试正常执行 ===");
userService.addUser("张三");
System.out.println("\n=== 测试抛出异常 ===");
try {
userService.deleteUser(-1);
} catch (Exception e) {
System.out.println("捕获到异常:" + e.getMessage());
}
}
}
使用AspectJ LTW(加载时织入)
// 配置META-INF/aop.xml
<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<aspects>
<aspect name="com.example.LoggingAspect"/>
</aspects>
<weaver>
<include within="com.example..*"/>
</weaver>
</aspectj>
实际应用场景示例
@Aspect
@Component
public class TransactionManagementAspect {
// 后置通知:关闭数据库连接
@After("execution(* com.example.dao.*.save*(..))")
public void closeConnection(JoinPoint joinPoint) {
System.out.println("关闭数据库连接");
// 实际应用中释放连接资源
}
// 后置通知:记录操作日志
@After("execution(* com.example.service.*.*(..)) && !execution(* com.example.service.*.get*(..))")
public void logOperation(JoinPoint joinPoint) {
String method = joinPoint.getSignature().getName();
String user = SecurityContextHolder.getContext().getAuthentication().getName();
System.out.println(String.format("用户[%s]执行了操作[%s]", user, method));
}
// 后置通知:清理缓存
@After("execution(* com.example.service.*.update*(..))")
public void clearCache(JoinPoint joinPoint) {
String entityName = joinPoint.getTarget().getClass().getSimpleName();
CacheManager.clearCache(entityName);
System.out.println("清理了" + entityName + "的缓存");
}
}
关键要点
- @After:无论方法正常结束还是抛出异常都执行
- @AfterReturning:只在方法正常返回时执行
- @AfterThrowing:只在方法抛出异常时执行
- JoinPoint:可以获取目标方法的信息
这种实现方式广泛应用于日志记录、事务管理、权限检查、性能监控等场景。