← 返回首页

Spring AOP详解

📂 java ⏱ 3 min 438 words

什么是AOP

AOP(Aspect-Oriented Programming)面向切面编程,用于分离横切关注点,如日志、事务、安全等。

AOP核心概念

import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LogAspect {
    @Pointcut("execution(* com.example.service.*.*(..))")
    public void serviceLayer() {}

    @Before("serviceLayer()")
    public void beforeMethod(JoinPoint joinPoint) {
        System.out.println("方法执行前: " + joinPoint.getSignature().getName());
    }

    @After("serviceLayer()")
    public void afterMethod(JoinPoint joinPoint) {
        System.out.println("方法执行后: " + joinPoint.getSignature().getName());
    }

    @Around("serviceLayer()")
    public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = joinPoint.proceed();
        long elapsed = System.currentTimeMillis() - start;
        System.out.println("方法耗时: " + elapsed + "ms");
        return result;
    }

    @AfterReturning(pointcut = "serviceLayer()", returning = "result")
    public void afterReturning(Object result) {
        System.out.println("方法返回: " + result);
    }

    @AfterThrowing(pointcut = "serviceLayer()", throwing = "ex")
    public void afterThrowing(Exception ex) {
        System.out.println("方法异常: " + ex.getMessage());
    }
}

切入点表达式

import org.aspectj.lang.annotation.*;

@Aspect
public class PointcutDemo {
    @Pointcut("execution(* com.example.service.*.*(..))")
    public void allServiceMethods() {}

    @Pointcut("execution(public * *(..))")
    public void allPublicMethods() {}

    @Pointcut("within(com.example.service..*)")
    public void inServicePackage() {}

    @Pointcut("bean(userService)")
    public void userServiceBean() {}

    @Pointcut("@annotation(com.example.annotation.Loggable)")
    public void loggableMethods() {}
}

AOP实战:日志记录

import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;

@Aspect
@Component
public class LoggingAspect {
    @Before("execution(* com.example.controller.*.*(..))")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("[" + LocalDateTime.now() + "] 调用: " +
            joinPoint.getSignature().toShortString());
    }

    @AfterReturning(pointcut = "execution(* com.example.controller.*.*(..))",
                    returning = "result")
    public void logAfter(JoinPoint joinPoint, Object result) {
        System.out.println("[" + LocalDateTime.now() + "] 返回: " + result);
    }
}

AOP实战:性能监控

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class PerformanceAspect {
    @Around("@annotation(com.example.annotation.PerformanceMonitor)")
    public Object monitorPerformance(ProceedingJoinPoint joinPoint) throws Throwable {
        String methodName = joinPoint.getSignature().getName();
        long start = System.currentTimeMillis();

        Object result = joinPoint.proceed();

        long elapsed = System.currentTimeMillis() - start;
        System.out.println("性能监控 - " + methodName + " 耗时: " + elapsed + "ms");
        return result;
    }
}

AOP实战:事务管理

import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class TransactionAspect {
    @Autowired
    private TransactionManager transactionManager;

    @Around("execution(* com.example.service.*.*(..))")
    public Object manageTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
        TransactionStatus status = transactionManager.getTransaction(
            new DefaultTransactionDefinition());

        try {
            Object result = joinPoint.proceed();
            transactionManager.commit(status);
            return result;
        } catch (Exception e) {
            transactionManager.rollback(status);
            throw e;
        }
    }
}

AOP实战:安全检查

import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class SecurityAspect {
    @Before("@annotation(com.example.annotation.RequiresRole)")
    public void checkPermission(JoinPoint joinPoint) {
        System.out.println("检查用户权限...");
    }

    @Around("@annotation(com.example.annotation.Secured)")
    public Object secureMethod(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("安全验证中...");
        Object result = joinPoint.proceed();
        System.out.println("安全验证完成");
        return result;
    }
}

AOP实战:缓存

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import java.util.concurrent.ConcurrentHashMap;

@Aspect
@Component
public class CacheAspect {
    private final ConcurrentHashMap<String, Object> cache = new ConcurrentHashMap<>();

    @Around("@annotation(com.example.annotation.Cachable)")
    public Object cacheResult(ProceedingJoinPoint joinPoint) throws Throwable {
        String key = joinPoint.getSignature().getName() +
            java.util.Arrays.toString(joinPoint.getArgs());

        if (cache.containsKey(key)) {
            System.out.println("从缓存返回: " + key);
            return cache.get(key);
        }

        Object result = joinPoint.proceed();
        cache.put(key, result);
        System.out.println("缓存结果: " + key);
        return result;
    }
}

启用AOP

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy
public class AopConfig {
}

AOP最佳实践

  1. 使用@Around处理复杂逻辑
  2. 合理使用切入点表达式
  3. 避免过度使用AOP影响性能
  4. AOP通知中避免异常
  5. 使用@Order控制通知执行顺序

总结

Spring AOP提供了强大的面向切面编程能力。掌握AOP的使用,能帮助你优雅地处理横切关注点。