Java后置通知案例如何实现

wen java案例 22

Java后置通知(After Advice)实现案例

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

Java后置通知案例如何实现

基于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 + "的缓存");
    }
}

关键要点

  1. @After:无论方法正常结束还是抛出异常都执行
  2. @AfterReturning:只在方法正常返回时执行
  3. @AfterThrowing:只在方法抛出异常时执行
  4. JoinPoint:可以获取目标方法的信息

这种实现方式广泛应用于日志记录、事务管理、权限检查、性能监控等场景。

抱歉,评论功能暂时关闭!