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. 设计要点
- 可扩展性:通过基类提供默认实现,子类可以覆盖特定方法
- 灵活性:通过注解配置切面的行为和属性
- 模块化:将不同关注点(日志、性能、重试等)分离到不同切面
- 可维护性:通用逻辑集中在基类中,减少重复代码
- 可读性:清晰的阶段划分(before/after/exception/finally)
这个设计可以根据实际需求进一步扩展,例如添加缓存、权限控制、限流等横切关注点。

浙公网安备 33010602011771号