【附录】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框架企业级特性的重要组成部分。

相关推荐
文心快码BaiduComate1 天前
来WAVE SUMMIT,文心快码升级亮点抢先看!
前端·后端·程序员
布列瑟农的星空1 天前
html中获取容器部署的环境变量
运维·前端·后端
用户298698530141 天前
如何在 C# 中将 Word 转换为 PostScript?
后端
AAA修煤气灶刘哥1 天前
MQ 可靠性血泪史:从丢消息到稳如老狗,后端 er 必看避坑指南
后端·spring cloud·rabbitmq
Java微观世界1 天前
final的隐藏技能:从代码规范到线程安全,你用对了吗?
后端
该用户已不存在1 天前
Node.js 做 Web 后端优势为什么这么大?
javascript·后端·node.js
on the way 1231 天前
Spring WebFlux 流式数据拉取与推送的实现
java·后端·spring
风一样的树懒1 天前
P0:消息序列化失败,Failed Fast导致无限重启
后端
龙在天1 天前
分库分表下的分页查询,到底怎么搞?
前端·后端
小蒜学长1 天前
基于Hadoop的网约车公司数据分析系统设计(代码+数据库+LW)
java·大数据·数据库·hadoop·spring boot·后端