AOP通用设计流程

通用AOP环绕通知实现

下面我将设计一个通用的AOP环绕通知实现,使用Spring AOP作为示例,但设计思想可以应用于其他AOP框架。

1. 基础实现

1.1 定义注解

首先定义一个用于标记需要环绕通知的注解:

import java.lang.annotation.*;

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AroundAdvice {
    /**
     * 切面名称
     */
    String name() default "";
    
    /**
     * 执行顺序,数值越小优先级越高
     */
    int order() default 0;
    
    /**
     * 异常处理类
     */
    Class<? extends Throwable>[] exceptions() default {};
}

1.2 环绕通知切面基类

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Aspect
@Component
public class GenericAroundAspect {

    @Around("@annotation(aroundAdvice)")
    @Order // 使用注解中的order值
    public Object aroundAdvice(ProceedingJoinPoint joinPoint, AroundAdvice aroundAdvice) throws Throwable {
        // 获取方法信息
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        String methodName = method.getName();
        String className = joinPoint.getTarget().getClass().getSimpleName();
        
        // 前置处理
        beforeAdvice(className, methodName, joinPoint.getArgs(), aroundAdvice);
        
        try {
            // 执行目标方法
            Object result = joinPoint.proceed();
            
            // 后置处理
            afterReturningAdvice(className, methodName, result, aroundAdvice);
            
            return result;
        } catch (Throwable ex) {
            // 异常处理
            afterThrowingAdvice(className, methodName, ex, aroundAdvice);
            throw ex;
        } finally {
            // 最终处理
            afterFinallyAdvice(className, methodName, aroundAdvice);
        }
    }
    
    protected void beforeAdvice(String className, String methodName, Object[] args, AroundAdvice aroundAdvice) {
        // 默认实现,子类可覆盖
        System.out.printf("[BEFORE] %s.%s() with args: %s%n", className, methodName, args);
    }
    
    protected void afterReturningAdvice(String className, String methodName, Object result, AroundAdvice aroundAdvice) {
        // 默认实现,子类可覆盖
        System.out.printf("[AFTER-RETURNING] %s.%s() returned: %s%n", className, methodName, result);
    }
    
    protected void afterThrowingAdvice(String className, String methodName, Throwable ex, AroundAdvice aroundAdvice) {
        // 默认实现,子类可覆盖
        System.err.printf("[AFTER-THROWING] %s.%s() threw exception: %s%n", className, methodName, ex.getMessage());
    }
    
    protected void afterFinallyAdvice(String className, String methodName, AroundAdvice aroundAdvice) {
        // 默认实现,子类可覆盖
        System.out.printf("[AFTER-FINALLY] %s.%s() completed%n", className, methodName);
    }
}

2. 扩展实现

2.1 自定义切面实现

import org.springframework.stereotype.Component;

@Aspect
@Component
public class CustomAroundAspect extends GenericAroundAspect {
    
    @Override
    protected void beforeAdvice(String className, String methodName, Object[] args, AroundAdvice aroundAdvice) {
        // 自定义前置处理逻辑
        System.out.printf("[CUSTOM-BEFORE] %s.%s() with advice: %s%n", 
            className, methodName, aroundAdvice.name());
    }
    
    @Override
    protected void afterReturningAdvice(String className, String methodName, Object result, AroundAdvice aroundAdvice) {
        // 自定义返回后处理逻辑
        if (result != null) {
            System.out.printf("[CUSTOM-AFTER] %s.%s() returned type: %s%n", 
                className, methodName, result.getClass().getSimpleName());
        }
    }
}

2.2 使用示例

@Service
public class SampleService {
    
    @AroundAdvice(name = "sampleMethod", order = 1, exceptions = {IllegalArgumentException.class})
    public String sampleMethod(String input) {
        if (input == null) {
            throw new IllegalArgumentException("Input cannot be null");
        }
        return "Processed: " + input;
    }
    
    @AroundAdvice(name = "anotherMethod", order = 2)
    public int anotherMethod(int a, int b) {
        return a + b;
    }
}

3. 高级特性实现

3.1 添加性能监控

public abstract class PerformanceMonitoringAspect extends GenericAroundAspect {
    
    @Override
    protected void beforeAdvice(String className, String methodName, Object[] args, AroundAdvice aroundAdvice) {
        long startTime = System.currentTimeMillis();
        getRequestContext().setAttribute("startTime", startTime);
    }
    
    @Override
    protected void afterFinallyAdvice(String className, String methodName, AroundAdvice aroundAdvice) {
        long startTime = (long) getRequestContext().getAttribute("startTime");
        long duration = System.currentTimeMillis() - startTime;
        System.out.printf("[PERFORMANCE] %s.%s() took %d ms%n", className, methodName, duration);
        
        // 可以记录到监控系统
        recordPerformanceMetric(className, methodName, duration);
    }
    
    protected abstract Object getRequestContext();
    protected abstract void recordPerformanceMetric(String className, String methodName, long duration);
}

3.2 添加重试机制

public abstract class RetryableAspect extends GenericAroundAspect {
    
    @Override
    public Object aroundAdvice(ProceedingJoinPoint joinPoint, AroundAdvice aroundAdvice) throws Throwable {
        int maxAttempts = getMaxAttempts(aroundAdvice);
        int attempts = 0;
        Throwable lastException;
        
        do {
            attempts++;
            try {
                return joinPoint.proceed();
            } catch (Throwable ex) {
                lastException = ex;
                if (shouldRetry(ex, aroundAdvice) {
                    System.out.printf("Retry attempt %d of %d for %s%n", 
                        attempts, maxAttempts, joinPoint.getSignature().getName());
                    Thread.sleep(getRetryDelay(attempts));
                } else {
                    throw ex;
                }
            }
        } while (attempts < maxAttempts);
        
        throw lastException;
    }
    
    protected int getMaxAttempts(AroundAdvice aroundAdvice) {
        return 3; // 默认重试3次
    }
    
    protected long getRetryDelay(int attempt) {
        return attempt * 1000L; // 指数退避
    }
    
    protected boolean shouldRetry(Throwable ex, AroundAdvice aroundAdvice) {
        for (Class<? extends Throwable> exceptionType : aroundAdvice.exceptions()) {
            if (exceptionType.isInstance(ex)) {
                return true;
            }
        }
        return false;
    }
}

4. 配置说明

4.1 Spring Boot配置

确保在Spring Boot启动类上添加@EnableAspectJAutoProxy

@SpringBootApplication
@EnableAspectJAutoProxy
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

4.2 切面执行顺序控制

使用@Order注解或实现Ordered接口来控制切面执行顺序。在基类中已经通过@Order注解支持从AroundAdvice注解中获取order值。

5. 设计要点

  1. 可扩展性:通过基类提供默认实现,子类可以覆盖特定方法
  2. 灵活性:通过注解配置切面的行为和属性
  3. 模块化:将不同关注点(日志、性能、重试等)分离到不同切面
  4. 可维护性:通用逻辑集中在基类中,减少重复代码
  5. 可读性:清晰的阶段划分(before/after/exception/finally)

这个设计可以根据实际需求进一步扩展,例如添加缓存、权限控制、限流等横切关注点。

posted @ 2025-04-26 15:45  月朗星希  阅读(20)  评论(0)    收藏  举报