【附录】Spring AOP 基础知识及应用

此文是 【Spring 容器详解】-> 【ApplicationContext 做了哪些企业化的增强?】的支节点。

Spring的AOP支持(Aspect-Oriented Programming)是ApplicationContext相对于BeanFactory的重要企业级增强功能。AOP允许开发者将横切关注点(如日志、事务、安全等)从业务逻辑中分离出来,实现更好的代码组织和维护性。

1. BeanFactory的AOP支持限制

1.1 BeanFactory的局限性

BeanFactory作为Spring的核心容器,在AOP支持方面存在以下限制:

  • 无内置AOP支持:BeanFactory本身不提供AOP功能
  • 缺乏切面管理:无法管理切面(Aspect)的生命周期
  • 无AOP注解支持:不支持@Aspect、@Before等AOP注解
  • AOP配置复杂:需要手动配置代理工厂和切面

1.2 示例代码

java 复制代码
// BeanFactory缺乏AOP支持
public class BeanFactoryAopExample {
    
    public static void main(String[] args) {
        // 创建BeanFactory
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        
        // BeanFactory本身不提供AOP功能
        // 无法使用@Aspect注解
        // 无法自动配置AOP代理
        // 需要通过其他方式实现横切关注点
        
        // 手动实现日志记录
        UserService userService = new UserService();
        
        // 手动添加日志
        System.out.println("方法开始执行: getUserById");
        try {
            User user = userService.getUserById(1L);
            System.out.println("方法执行成功: getUserById");
            return user;
        } catch (Exception e) {
            System.out.println("方法执行异常: getUserById, 异常: " + e.getMessage());
            throw e;
        }
    }
}

class UserService {
    public User getUserById(Long id) {
        // 业务逻辑
        return new User(id, "User " + id);
    }
}

2. ApplicationContext的AOP支持扩展

2.1 核心注解:@EnableAspectJAutoProxy

ApplicationContext通过@EnableAspectJAutoProxy启用AOP功能:

java 复制代码
@Configuration
@EnableAspectJAutoProxy
public class AopConfig {
    
    @Bean
    public LoggingAspect loggingAspect() {
        return new LoggingAspect();
    }
    
    @Bean
    public TransactionAspect transactionAspect() {
        return new TransactionAspect();
    }
    
    @Bean
    public SecurityAspect securityAspect() {
        return new SecurityAspect();
    }
}

2.2 AOP支持的核心功能

2.2.1 切面(Aspect)管理

Spring自动管理切面的生命周期,包括创建、初始化和销毁:

java 复制代码
@Aspect
@Component
public class LoggingAspect {
    
    private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
    
    // 前置通知
    @Before("execution(* com.example.service.*.*(..))")
    public void logBefore(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        String className = joinPoint.getTarget().getClass().getSimpleName();
        Object[] args = joinPoint.getArgs();
        
        logger.info("执行方法: {}.{}, 参数: {}", className, methodName, Arrays.toString(args));
    }
    
    // 后置通知
    @After("execution(* com.example.service.*.*(..))")
    public void logAfter(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        String className = joinPoint.getTarget().getClass().getSimpleName();
        
        logger.info("方法执行完成: {}.{}", className, methodName);
    }
    
    // 返回通知
    @AfterReturning(pointcut = "execution(* com.example.service.*.*(..))", returning = "result")
    public void logAfterReturning(JoinPoint joinPoint, Object result) {
        String methodName = joinPoint.getSignature().getName();
        String className = joinPoint.getTarget().getClass().getSimpleName();
        
        logger.info("方法执行成功: {}.{}, 返回值: {}", className, methodName, result);
    }
    
    // 异常通知
    @AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))", throwing = "error")
    public void logAfterThrowing(JoinPoint joinPoint, Throwable error) {
        String methodName = joinPoint.getSignature().getName();
        String className = joinPoint.getTarget().getClass().getSimpleName();
        
        logger.error("方法执行异常: {}.{}, 异常: {}", className, methodName, error.getMessage());
    }
    
    // 环绕通知
    @Around("execution(* com.example.service.*.*(..))")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        String methodName = joinPoint.getSignature().getName();
        String className = joinPoint.getTarget().getClass().getSimpleName();
        
        long startTime = System.currentTimeMillis();
        logger.info("开始执行方法: {}.{}", className, methodName);
        
        try {
            Object result = joinPoint.proceed();
            long endTime = System.currentTimeMillis();
            logger.info("方法执行完成: {}.{}, 耗时: {}ms", className, methodName, (endTime - startTime));
            return result;
        } catch (Throwable e) {
            long endTime = System.currentTimeMillis();
            logger.error("方法执行异常: {}.{}, 耗时: {}ms, 异常: {}", 
                className, methodName, (endTime - startTime), e.getMessage());
            throw e;
        }
    }
}

2.2.2 切点表达式(Pointcut Expression)

Spring支持丰富的切点表达式语法:

java 复制代码
@Aspect
@Component
public class PointcutExample {
    
    // 1. 方法执行切点
    @Pointcut("execution(* com.example.service.*.*(..))")
    public void serviceMethods() {}
    
    // 2. 方法参数切点
    @Pointcut("execution(* *.*(Long, String))")
    public void methodsWithLongAndString() {}
    
    // 3. 注解切点
    @Pointcut("@annotation(com.example.annotation.Logged)")
    public void loggedMethods() {}
    
    // 4. 类切点
    @Pointcut("within(com.example.service.*)")
    public void serviceClasses() {}
    
    // 5. 组合切点
    @Pointcut("serviceMethods() && loggedMethods()")
    public void loggedServiceMethods() {}
    
    // 6. 参数切点
    @Pointcut("args(Long)")
    public void methodsWithLongParam() {}
    
    // 7. 返回值切点
    @Pointcut("execution(* *.*(..)) && !execution(void *.*(..))")
    public void methodsWithReturnValue() {}
    
    // 8. 异常切点
    @Pointcut("execution(* *.*(..)) throws Exception")
    public void methodsThrowingException() {}
    
    // 使用切点
    @Before("serviceMethods()")
    public void beforeServiceMethod(JoinPoint joinPoint) {
        System.out.println("服务方法执行前: " + joinPoint.getSignature().getName());
    }
    
    @Before("loggedMethods()")
    public void beforeLoggedMethod(JoinPoint joinPoint) {
        System.out.println("日志方法执行前: " + joinPoint.getSignature().getName());
    }
    
    @Before("loggedServiceMethods()")
    public void beforeLoggedServiceMethod(JoinPoint joinPoint) {
        System.out.println("日志服务方法执行前: " + joinPoint.getSignature().getName());
    }
}

3. AOP通知类型详解

3.1 前置通知(@Before)

java 复制代码
@Aspect
@Component
public class BeforeAdviceExample {
    
    // 基本前置通知
    @Before("execution(* com.example.service.UserService.*(..))")
    public void beforeUserServiceMethod(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        
        System.out.println("用户服务方法执行前: " + methodName);
        System.out.println("方法参数: " + Arrays.toString(args));
    }
    
    // 带条件的前置通知
    @Before("execution(* com.example.service.*.*(..)) && args(id,..)")
    public void beforeMethodWithId(Long id, JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        
        if (id > 0) {
            System.out.println("方法 " + methodName + " 执行前,ID: " + id);
        } else {
            System.out.println("警告:方法 " + methodName + " 使用了无效ID: " + id);
        }
    }
    
    // 权限检查前置通知
    @Before("execution(* com.example.service.*.*(..)) && @annotation(secured)")
    public void checkPermission(Secured secured, JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        String[] roles = secured.roles();
        
        // 检查当前用户是否有权限
        if (!hasPermission(roles)) {
            throw new SecurityException("用户没有权限执行方法: " + methodName);
        }
        
        System.out.println("权限检查通过,执行方法: " + methodName);
    }
    
    private boolean hasPermission(String[] roles) {
        // 实现权限检查逻辑
        return true; // 简化实现
    }
}

// 安全注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Secured {
    String[] roles() default {};
}

3.2 后置通知(@After)

java 复制代码
@Aspect
@Component
public class AfterAdviceExample {
    
    // 基本后置通知
    @After("execution(* com.example.service.*.*(..))")
    public void afterMethod(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        String className = joinPoint.getTarget().getClass().getSimpleName();
        
        System.out.println("方法执行完成: " + className + "." + methodName);
    }
    
    // 资源清理后置通知
    @After("execution(* com.example.service.*.*(..))")
    public void cleanupResources(JoinPoint joinPoint) {
        // 清理资源
        System.out.println("清理方法执行后的资源");
    }
    
    // 审计日志后置通知
    @After("execution(* com.example.service.*.*(..)) && @annotation(audited)")
    public void auditLog(Audited audited, JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        String operation = audited.operation();
        
        System.out.println("审计日志: 操作=" + operation + ", 方法=" + methodName);
    }
}

// 审计注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Audited {
    String operation() default "";
}

3.3 返回通知(@AfterReturning)

java 复制代码
@Aspect
@Component
public class AfterReturningAdviceExample {
    
    // 基本返回通知
    @AfterReturning(pointcut = "execution(* com.example.service.*.*(..))", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) {
        String methodName = joinPoint.getSignature().getName();
        
        System.out.println("方法 " + methodName + " 执行成功,返回值: " + result);
    }
    
    // 带类型的返回通知
    @AfterReturning(pointcut = "execution(* com.example.service.UserService.getUserById(..))", 
                    returning = "user")
    public void afterReturningUser(JoinPoint joinPoint, User user) {
        if (user != null) {
            System.out.println("成功获取用户: " + user.getName());
        } else {
            System.out.println("用户不存在");
        }
    }
    
    // 结果验证返回通知
    @AfterReturning(pointcut = "execution(* com.example.service.*.*(..))", 
                    returning = "result")
    public void validateResult(JoinPoint joinPoint, Object result) {
        if (result instanceof Collection) {
            Collection<?> collection = (Collection<?>) result;
            if (collection.isEmpty()) {
                System.out.println("警告:方法返回空集合");
            }
        }
    }
    
    // 缓存更新返回通知
    @AfterReturning(pointcut = "execution(* com.example.service.*.*(..))", 
                    returning = "result")
    public void updateCache(JoinPoint joinPoint, Object result) {
        // 更新缓存
        System.out.println("更新缓存,方法: " + joinPoint.getSignature().getName());
    }
}

3.4 异常通知(@AfterThrowing)

java 复制代码
@Aspect
@Component
public class AfterThrowingAdviceExample {
    
    // 基本异常通知
    @AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))", throwing = "error")
    public void afterThrowing(JoinPoint joinPoint, Throwable error) {
        String methodName = joinPoint.getSignature().getName();
        String className = joinPoint.getTarget().getClass().getSimpleName();
        
        System.err.println("方法执行异常: " + className + "." + methodName);
        System.err.println("异常类型: " + error.getClass().getSimpleName());
        System.err.println("异常消息: " + error.getMessage());
    }
    
    // 特定异常通知
    @AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))", 
                   throwing = "sqlException")
    public void handleSqlException(JoinPoint joinPoint, SQLException sqlException) {
        String methodName = joinPoint.getSignature().getName();
        
        System.err.println("SQL异常: " + methodName + ", 错误代码: " + sqlException.getErrorCode());
        
        // 记录SQL异常到日志
        logSqlException(methodName, sqlException);
    }
    
    // 异常分类处理
    @AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))", 
                   throwing = "error")
    public void categorizeException(JoinPoint joinPoint, Throwable error) {
        if (error instanceof RuntimeException) {
            handleRuntimeException(joinPoint, (RuntimeException) error);
        } else if (error instanceof Exception) {
            handleCheckedException(joinPoint, (Exception) error);
        } else {
            handleError(joinPoint, (Error) error);
        }
    }
    
    private void handleRuntimeException(JoinPoint joinPoint, RuntimeException e) {
        System.err.println("运行时异常: " + e.getMessage());
    }
    
    private void handleCheckedException(JoinPoint joinPoint, Exception e) {
        System.err.println("检查异常: " + e.getMessage());
    }
    
    private void handleError(JoinPoint joinPoint, Error e) {
        System.err.println("严重错误: " + e.getMessage());
    }
    
    private void logSqlException(String methodName, SQLException e) {
        // 实现SQL异常日志记录
        System.err.println("记录SQL异常: " + methodName + " - " + e.getMessage());
    }
}

3.5 环绕通知(@Around)

java 复制代码
@Aspect
@Component
public class AroundAdviceExample {
    
    // 性能监控环绕通知
    @Around("execution(* com.example.service.*.*(..))")
    public Object performanceMonitor(ProceedingJoinPoint joinPoint) throws Throwable {
        String methodName = joinPoint.getSignature().getName();
        String className = joinPoint.getTarget().getClass().getSimpleName();
        
        long startTime = System.currentTimeMillis();
        System.out.println("开始执行方法: " + className + "." + methodName);
        
        try {
            Object result = joinPoint.proceed();
            long endTime = System.currentTimeMillis();
            long duration = endTime - startTime;
            
            System.out.println("方法执行成功: " + className + "." + methodName + ", 耗时: " + duration + "ms");
            
            // 记录性能指标
            if (duration > 1000) {
                System.out.println("警告:方法执行时间过长: " + duration + "ms");
            }
            
            return result;
        } catch (Throwable e) {
            long endTime = System.currentTimeMillis();
            long duration = endTime - startTime;
            
            System.err.println("方法执行异常: " + className + "." + methodName + ", 耗时: " + duration + "ms");
            System.err.println("异常: " + e.getMessage());
            throw e;
        }
    }
    
    // 重试机制环绕通知
    @Around("execution(* com.example.service.*.*(..)) && @annotation(retryable)")
    public Object retryOperation(ProceedingJoinPoint joinPoint, Retryable retryable) throws Throwable {
        int maxAttempts = retryable.maxAttempts();
        long delay = retryable.delay();
        
        for (int attempt = 1; attempt <= maxAttempts; attempt++) {
            try {
                System.out.println("尝试执行方法,第 " + attempt + " 次");
                return joinPoint.proceed();
            } catch (Exception e) {
                if (attempt == maxAttempts) {
                    System.err.println("重试次数已达上限,抛出异常");
                    throw e;
                }
                
                System.out.println("执行失败,等待 " + delay + "ms 后重试");
                Thread.sleep(delay);
            }
        }
        
        throw new RuntimeException("重试失败");
    }
    
    // 缓存环绕通知
    @Around("execution(* com.example.service.*.*(..)) && @annotation(cached)")
    public Object cacheOperation(ProceedingJoinPoint joinPoint, Cached cached) throws Throwable {
        String cacheKey = generateCacheKey(joinPoint);
        
        // 尝试从缓存获取
        Object cachedResult = getFromCache(cacheKey);
        if (cachedResult != null) {
            System.out.println("从缓存获取结果: " + cacheKey);
            return cachedResult;
        }
        
        // 执行方法
        Object result = joinPoint.proceed();
        
        // 存入缓存
        putToCache(cacheKey, result, cached.ttl());
        System.out.println("结果已缓存: " + cacheKey);
        
        return result;
    }
    
    private String generateCacheKey(ProceedingJoinPoint joinPoint) {
        return joinPoint.getSignature().getName() + "_" + Arrays.toString(joinPoint.getArgs());
    }
    
    private Object getFromCache(String key) {
        // 实现缓存获取逻辑
        return null;
    }
    
    private void putToCache(String key, Object value, long ttl) {
        // 实现缓存存储逻辑
    }
}

// 重试注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Retryable {
    int maxAttempts() default 3;
    long delay() default 1000;
}

// 缓存注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Cached {
    long ttl() default 300000; // 5分钟
}

4. 实际应用场景

4.1 事务管理

java 复制代码
@Aspect
@Component
public class TransactionAspect {
    
    @Autowired
    private PlatformTransactionManager transactionManager;
    
    @Around("@annotation(transactional)")
    public Object manageTransaction(ProceedingJoinPoint joinPoint, Transactional transactional) throws Throwable {
        TransactionStatus status = null;
        
        try {
            // 开启事务
            DefaultTransactionDefinition def = new DefaultTransactionDefinition();
            def.setPropagationBehavior(transactional.propagation().value());
            def.setIsolationLevel(transactional.isolation().value());
            def.setTimeout(transactional.timeout());
            def.setReadOnly(transactional.readOnly());
            
            status = transactionManager.getTransaction(def);
            
            // 执行方法
            Object result = joinPoint.proceed();
            
            // 提交事务
            transactionManager.commit(status);
            System.out.println("事务提交成功");
            
            return result;
        } catch (Throwable e) {
            // 回滚事务
            if (status != null) {
                transactionManager.rollback(status);
                System.err.println("事务回滚,异常: " + e.getMessage());
            }
            throw e;
        }
    }
}

@Service
public class TransactionalUserService {
    
    @Transactional(rollbackFor = Exception.class)
    public void createUserWithEmail(String username, String email) {
        // 创建用户
        createUser(username);
        
        // 发送欢迎邮件
        sendWelcomeEmail(email);
    }
    
    private void createUser(String username) {
        // 创建用户逻辑
    }
    
    private void sendWelcomeEmail(String email) {
        // 发送邮件逻辑
    }
}

4.2 安全控制

java 复制代码
@Aspect
@Component
public class SecurityAspect {
    
    @Autowired
    private SecurityContext securityContext;
    
    @Before("@annotation(secured)")
    public void checkSecurity(Secured secured, JoinPoint joinPoint) {
        String[] requiredRoles = secured.roles();
        String currentUser = getCurrentUser();
        String[] userRoles = getUserRoles(currentUser);
        
        if (!hasRequiredRole(userRoles, requiredRoles)) {
            throw new SecurityException("用户 " + currentUser + " 没有权限执行此操作");
        }
        
        System.out.println("安全检查通过,用户: " + currentUser + ", 角色: " + Arrays.toString(userRoles));
    }
    
    @Before("@annotation(rateLimited)")
    public void checkRateLimit(RateLimited rateLimited, JoinPoint joinPoint) {
        String key = generateRateLimitKey(joinPoint);
        int limit = rateLimited.limit();
        int window = rateLimited.window();
        
        if (isRateLimitExceeded(key, limit, window)) {
            throw new RateLimitExceededException("请求频率超限");
        }
        
        System.out.println("频率限制检查通过");
    }
    
    private String getCurrentUser() {
        // 获取当前用户
        return "currentUser";
    }
    
    private String[] getUserRoles(String user) {
        // 获取用户角色
        return new String[]{"USER"};
    }
    
    private boolean hasRequiredRole(String[] userRoles, String[] requiredRoles) {
        // 检查用户是否有所需角色
        return Arrays.stream(requiredRoles)
                .anyMatch(required -> Arrays.asList(userRoles).contains(required));
    }
    
    private String generateRateLimitKey(ProceedingJoinPoint joinPoint) {
        return joinPoint.getSignature().getName() + "_" + getCurrentUser();
    }
    
    private boolean isRateLimitExceeded(String key, int limit, int window) {
        // 实现频率限制检查
        return false;
    }
}

// 安全注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Secured {
    String[] roles();
}

// 频率限制注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RateLimited {
    int limit() default 100;
    int window() default 3600; // 1小时
}

class RateLimitExceededException extends RuntimeException {
    public RateLimitExceededException(String message) {
        super(message);
    }
}

4.3 日志记录

java 复制代码
@Aspect
@Component
public class LoggingAspect {
    
    private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
    
    @Around("@annotation(logged)")
    public Object logMethod(ProceedingJoinPoint joinPoint, Logged logged) throws Throwable {
        String methodName = joinPoint.getSignature().getName();
        String className = joinPoint.getTarget().getClass().getSimpleName();
        Object[] args = joinPoint.getArgs();
        
        // 记录方法调用
        logger.info("调用方法: {}.{}, 参数: {}", className, methodName, Arrays.toString(args));
        
        long startTime = System.currentTimeMillis();
        
        try {
            Object result = joinPoint.proceed();
            long duration = System.currentTimeMillis() - startTime;
            
            // 记录方法成功
            logger.info("方法执行成功: {}.{}, 耗时: {}ms, 返回值: {}", 
                className, methodName, duration, result);
            
            return result;
        } catch (Throwable e) {
            long duration = System.currentTimeMillis() - startTime;
            
            // 记录方法异常
            logger.error("方法执行异常: {}.{}, 耗时: {}ms, 异常: {}", 
                className, methodName, duration, e.getMessage(), e);
            
            throw e;
        }
    }
    
    @AfterThrowing(pointcut = "@annotation(logged)", throwing = "error")
    public void logException(JoinPoint joinPoint, Logged logged, Throwable error) {
        String methodName = joinPoint.getSignature().getName();
        String className = joinPoint.getTarget().getClass().getSimpleName();
        
        // 记录异常详情
        logger.error("方法异常详情: {}.{}, 异常类型: {}, 异常消息: {}", 
            className, methodName, error.getClass().getSimpleName(), error.getMessage());
        
        // 记录异常堆栈
        logger.error("异常堆栈:", error);
    }
}

// 日志注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Logged {
    String value() default "";
    boolean logArgs() default true;
    boolean logResult() default true;
    boolean logException() default true;
}

@Service
public class LoggedUserService {
    
    @Logged("获取用户信息")
    public User getUserById(Long id) {
        return new User(id, "User " + id);
    }
    
    @Logged("创建用户")
    public User createUser(String name) {
        return new User(System.currentTimeMillis(), name);
    }
}

4.4 性能监控

java 复制代码
@Aspect
@Component
public class PerformanceMonitorAspect {
    
    private final Map<String, MethodStats> methodStats = new ConcurrentHashMap<>();
    
    @Around("@annotation(monitored)")
    public Object monitorPerformance(ProceedingJoinPoint joinPoint, Monitored monitored) throws Throwable {
        String methodName = joinPoint.getSignature().getName();
        String className = joinPoint.getTarget().getClass().getSimpleName();
        String key = className + "." + methodName;
        
        long startTime = System.nanoTime();
        long startMemory = getCurrentMemoryUsage();
        
        try {
            Object result = joinPoint.proceed();
            
            long duration = System.nanoTime() - startTime;
            long memoryUsed = getCurrentMemoryUsage() - startMemory;
            
            // 更新统计信息
            updateStats(key, duration, memoryUsed, true);
            
            // 检查性能阈值
            checkPerformanceThreshold(key, duration, memoryUsed, monitored);
            
            return result;
        } catch (Throwable e) {
            long duration = System.nanoTime() - startTime;
            long memoryUsed = getCurrentMemoryUsage() - startMemory;
            
            // 更新统计信息
            updateStats(key, duration, memoryUsed, false);
            
            throw e;
        }
    }
    
    private void updateStats(String key, long duration, long memoryUsed, boolean success) {
        methodStats.compute(key, (k, stats) -> {
            if (stats == null) {
                stats = new MethodStats();
            }
            
            stats.incrementCallCount();
            stats.addDuration(duration);
            stats.addMemoryUsage(memoryUsed);
            
            if (success) {
                stats.incrementSuccessCount();
            } else {
                stats.incrementFailureCount();
            }
            
            return stats;
        });
    }
    
    private void checkPerformanceThreshold(String key, long duration, long memoryUsed, Monitored monitored) {
        long durationMs = duration / 1_000_000; // 转换为毫秒
        
        if (durationMs > monitored.durationThreshold()) {
            System.err.println("性能警告: 方法 " + key + " 执行时间 " + durationMs + "ms 超过阈值 " + monitored.durationThreshold() + "ms");
        }
        
        if (memoryUsed > monitored.memoryThreshold()) {
            System.err.println("内存警告: 方法 " + key + " 内存使用 " + memoryUsed + " bytes 超过阈值 " + monitored.memoryThreshold() + " bytes");
        }
    }
    
    private long getCurrentMemoryUsage() {
        Runtime runtime = Runtime.getRuntime();
        return runtime.totalMemory() - runtime.freeMemory();
    }
    
    // 获取性能统计信息
    public Map<String, MethodStats> getMethodStats() {
        return new HashMap<>(methodStats);
    }
    
    // 重置统计信息
    public void resetStats() {
        methodStats.clear();
    }
    
    // 方法统计信息类
    public static class MethodStats {
        private long callCount = 0;
        private long successCount = 0;
        private long failureCount = 0;
        private long totalDuration = 0;
        private long totalMemoryUsage = 0;
        private long minDuration = Long.MAX_VALUE;
        private long maxDuration = 0;
        
        public void incrementCallCount() { callCount++; }
        public void incrementSuccessCount() { successCount++; }
        public void incrementFailureCount() { failureCount++; }
        
        public void addDuration(long duration) {
            totalDuration += duration;
            minDuration = Math.min(minDuration, duration);
            maxDuration = Math.max(maxDuration, duration);
        }
        
        public void addMemoryUsage(long memoryUsage) {
            totalMemoryUsage += memoryUsage;
        }
        
        // getter方法
        public long getCallCount() { return callCount; }
        public long getSuccessCount() { return successCount; }
        public long getFailureCount() { return failureCount; }
        public double getAverageDuration() { return callCount > 0 ? (double) totalDuration / callCount : 0; }
        public long getMinDuration() { return minDuration == Long.MAX_VALUE ? 0 : minDuration; }
        public long getMaxDuration() { return maxDuration; }
        public double getAverageMemoryUsage() { return callCount > 0 ? (double) totalMemoryUsage / callCount : 0; }
        public double getSuccessRate() { return callCount > 0 ? (double) successCount / callCount : 0; }
    }
}

// 性能监控注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Monitored {
    long durationThreshold() default 1000; // 1秒
    long memoryThreshold() default 1024 * 1024; // 1MB
}

@Service
public class MonitoredUserService {
    
    @Monitored(durationThreshold = 500, memoryThreshold = 512 * 1024)
    public User getUserById(Long id) {
        // 模拟耗时操作
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        return new User(id, "User " + id);
    }
}

5. 高级特性

5.1 自定义切点

java 复制代码
@Aspect
@Component
public class CustomPointcutAspect {
    
    // 自定义切点:业务方法
    @Pointcut("execution(* com.example.business.*.*(..))")
    public void businessMethods() {}
    
    // 自定义切点:数据访问方法
    @Pointcut("execution(* com.example.repository.*.*(..))")
    public void dataAccessMethods() {}
    
    // 自定义切点:服务方法
    @Pointcut("execution(* com.example.service.*.*(..))")
    public void serviceMethods() {}
    
    // 自定义切点:控制器方法
    @Pointcut("execution(* com.example.controller.*.*(..))")
    public void controllerMethods() {}
    
    // 组合切点:业务逻辑层
    @Pointcut("businessMethods() || serviceMethods()")
    public void businessLayer() {}
    
    // 组合切点:数据访问层
    @Pointcut("dataAccessMethods()")
    public void dataLayer() {}
    
    // 组合切点:表现层
    @Pointcut("controllerMethods()")
    public void presentationLayer() {}
    
    // 使用自定义切点
    @Before("businessLayer()")
    public void beforeBusinessMethod(JoinPoint joinPoint) {
        System.out.println("业务方法执行前: " + joinPoint.getSignature().getName());
    }
    
    @After("dataLayer()")
    public void afterDataAccessMethod(JoinPoint joinPoint) {
        System.out.println("数据访问方法执行后: " + joinPoint.getSignature().getName());
    }
    
    @Around("presentationLayer()")
    public Object aroundControllerMethod(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("控制器方法执行前");
        Object result = joinPoint.proceed();
        System.out.println("控制器方法执行后");
        return result;
    }
}

5.2 切面优先级

java 复制代码
@Aspect
@Component
@Order(1) // 最高优先级
public class HighPriorityAspect {
    
    @Before("execution(* com.example.service.*.*(..))")
    public void highPriorityAdvice(JoinPoint joinPoint) {
        System.out.println("高优先级切面执行: " + joinPoint.getSignature().getName());
    }
}

@Aspect
@Component
@Order(2) // 中等优先级
public class MediumPriorityAspect {
    
    @Before("execution(* com.example.service.*.*(..))")
    public void mediumPriorityAdvice(JoinPoint joinPoint) {
        System.out.println("中等优先级切面执行: " + joinPoint.getSignature().getName());
    }
}

@Aspect
@Component
@Order(3) // 最低优先级
public class LowPriorityAspect {
    
    @Before("execution(* com.example.service.*.*(..))")
    public void lowPriorityAdvice(JoinPoint joinPoint) {
        System.out.println("低优先级切面执行: " + joinPoint.getSignature().getName());
    }
}

5.3 切面组合

java 复制代码
@Aspect
@Component
public class CompositeAspect {
    
    // 组合多个切点
    @Pointcut("execution(* com.example.service.*.*(..))")
    public void serviceMethods() {}
    
    @Pointcut("execution(* com.example.repository.*.*(..))")
    public void repositoryMethods() {}
    
    @Pointcut("serviceMethods() || repositoryMethods()")
    public void serviceOrRepositoryMethods() {}
    
    // 组合多个通知
    @Around("serviceOrRepositoryMethods()")
    public Object compositeAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        // 前置处理
        System.out.println("组合切面前置处理");
        
        // 执行方法
        Object result = joinPoint.proceed();
        
        // 后置处理
        System.out.println("组合切面后置处理");
        
        return result;
    }
    
    // 使用@Caching组合多个缓存操作
    @Caching(
        cacheable = {
            @Cacheable(value = "users", key = "#id")
        },
        put = {
            @CachePut(value = "userNames", key = "#result.name")
        },
        evict = {
            @CacheEvict(value = "userList", allEntries = true)
        }
    )
    public User getUserById(Long id) {
        // 获取用户逻辑
        return new User(id, "User " + id);
    }
}

6. 最佳实践

6.1 切面设计原则

java 复制代码
@Aspect
@Component
public class WellDesignedAspect {
    
    // 1. 单一职责原则:每个切面只负责一个横切关注点
    @Pointcut("execution(* com.example.service.*.*(..))")
    public void serviceMethods() {}
    
    // 2. 明确的切点表达式:避免过于宽泛的切点
    @Before("serviceMethods() && !execution(* *.get*(..))") // 排除getter方法
    public void beforeServiceMethod(JoinPoint joinPoint) {
        // 只处理非getter的服务方法
    }
    
    // 3. 合理的通知类型选择
    @Around("serviceMethods()") // 需要控制方法执行流程时使用@Around
    public Object aroundServiceMethod(ProceedingJoinPoint joinPoint) throws Throwable {
        // 复杂的横切逻辑
        return joinPoint.proceed();
    }
    
    @Before("serviceMethods()") // 简单的前置处理使用@Before
    public void beforeServiceMethodSimple(JoinPoint joinPoint) {
        // 简单的前置逻辑
    }
    
    // 4. 异常处理
    @AfterThrowing(pointcut = "serviceMethods()", throwing = "error")
    public void handleServiceException(JoinPoint joinPoint, Throwable error) {
        // 统一的异常处理逻辑
        logException(joinPoint, error);
        notifyAdministrator(joinPoint, error);
    }
    
    private void logException(JoinPoint joinPoint, Throwable error) {
        // 记录异常日志
    }
    
    private void notifyAdministrator(JoinPoint joinPoint, Throwable error) {
        // 通知管理员
    }
}

6.2 性能优化

java 复制代码
@Aspect
@Component
public class OptimizedAspect {
    
    // 1. 缓存切点表达式编译结果
    private final Pointcut serviceMethods = 
        new AspectJExpressionPointcut("execution(* com.example.service.*.*(..))");
    
    // 2. 使用条件表达式避免不必要的通知执行
    @Before("serviceMethods && args(id,..)")
    public void beforeServiceMethodWithId(Long id, JoinPoint joinPoint) {
        if (id > 0) { // 条件检查
            // 只处理有效的ID
            processValidId(id);
        }
    }
    
    // 3. 异步处理非关键通知
    @Async
    @AfterReturning("serviceMethods")
    public void asyncAfterReturning(JoinPoint joinPoint, Object result) {
        // 异步处理,不阻塞主流程
        processResultAsync(result);
    }
    
    // 4. 批量处理
    @AfterReturning("serviceMethods")
    public void batchProcess(JoinPoint joinPoint, Object result) {
        // 批量处理结果
        batchProcessor.add(result);
        
        if (batchProcessor.isFull()) {
            batchProcessor.process();
        }
    }
    
    private void processValidId(Long id) {
        // 处理有效ID的逻辑
    }
    
    private void processResultAsync(Object result) {
        // 异步处理结果
    }
}

@Component
public class BatchProcessor {
    private final List<Object> items = new ArrayList<>();
    private static final int BATCH_SIZE = 100;
    
    public void add(Object item) {
        items.add(item);
    }
    
    public boolean isFull() {
        return items.size() >= BATCH_SIZE;
    }
    
    public void process() {
        // 批量处理逻辑
        System.out.println("批量处理 " + items.size() + " 个项目");
        items.clear();
    }
}

6.3 测试策略

java 复制代码
@SpringBootTest
class AopTest {
    
    @Autowired
    private UserService userService;
    
    @Autowired
    private ApplicationContext applicationContext;
    
    @Test
    void testAopFunctionality() {
        // 测试AOP功能
        User user = userService.getUserById(1L);
        assertNotNull(user);
        
        // 验证切面是否被正确应用
        // 可以通过日志输出或其他方式验证
    }
    
    @Test
    void testAspectOrder() {
        // 测试切面执行顺序
        userService.getUserById(1L);
        
        // 验证切面按正确顺序执行
    }
    
    @Test
    void testPointcutExpression() {
        // 测试切点表达式
        userService.getUserById(1L);
        userService.createUser("Test User");
        
        // 验证切点表达式是否正确匹配
    }
}

// 测试用的切面
@Aspect
@Component
@TestConfiguration
public class TestAspect {
    
    private final List<String> executedAdvice = new ArrayList<>();
    
    @Before("execution(* com.example.service.*.*(..))")
    public void testAdvice(JoinPoint joinPoint) {
        executedAdvice.add(joinPoint.getSignature().getName());
    }
    
    public List<String> getExecutedAdvice() {
        return new ArrayList<>(executedAdvice);
    }
    
    public void clear() {
        executedAdvice.clear();
    }
}

总结

ApplicationContext在AOP支持方面相比BeanFactory提供了以下重要扩展,其核心特性:

  1. 切面(Aspect):横切关注点的模块化
  2. 切点(Pointcut):定义在哪些连接点应用通知
  3. 通知(Advice):在切点处要执行的代码
  4. 连接点(Join Point):程序执行过程中的某个特定点
  5. 目标对象(Target Object):被代理的对象

这些特性使得Spring应用能够优雅地处理横切关注点,实现更好的代码组织和维护性,是Spring框架企业级特性的重要组成部分。

相关推荐
Moonbit1 小时前
MoonBit 作者寄语 2025 级清华深圳新生
前端·后端·程序员
前端的阶梯1 小时前
开发一个支持支付功能的微信小程序的注意事项,含泪送上
前端·后端·全栈
咕噜分发企业签名APP加固彭于晏1 小时前
腾讯元器的优点是什么
前端·后端
AAA修煤气灶刘哥2 小时前
Swagger 用着糟心?试试 Knife4j,后端开发狂喜
后端·面试
bobz9652 小时前
MCP on windows
后端
泡海椒2 小时前
jquickexcel 全功能指南:从数据导入到精美导出的完整流程
后端
iOS开发上架哦3 小时前
移动端网页调试实战,键盘弹出与视口错位问题的定位与优化
后端
百度Geek说3 小时前
PaddleMIX推出扩散模型推理加速Fast-Diffusers:自研蒸馏加速方法FLUX-Lightning实现4步图像生成
后端
gopher_looklook3 小时前
Go并发实战:singleflight 源码解读与二次封装
数据结构·后端·go
用户833810251223 小时前
我为什么做PmMock:让接口设计不再头疼
前端·后端