Spring Boot自定义注解与AOP结合
自定义注解结合AOP可优雅实现横切关注点。
AOP依赖配置
XML
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
日志记录注解
定义注解
Java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogRecord {
String operation(); // 操作描述
String module(); // 模块名称
boolean saveResult() default true;
}
定义切面
Java
@Aspect
@Component
@Slf4j
public class LogRecordAspect {
@Around("@annotation(logRecord)")
public Object around(ProceedingJoinPoint joinPoint,
LogRecord logRecord) throws Throwable {
// 方法信息
String className = joinPoint.getTarget().getClass().getSimpleName();
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
// 前置日志
log.info("开始执行 {}.{} - 模块:{}, 操作:{}, 参数:{}",
className, methodName,
logRecord.module(), logRecord.operation(),
JsonUtil.toJson(args));
long startTime = System.currentTimeMillis();
try {
Object result = joinPoint.proceed();
// 成功日志
log.info("执行成功 {}.{} - 耗时:{}ms, 结果:{}",
className, methodName,
System.currentTimeMillis() - startTime,
logRecord.saveResult() ? JsonUtil.toJson(result) : "已忽略");
return result;
} catch (Exception e) {
// 异常日志
log.error("执行异常 {}.{} - 耗时:{}ms, 异常:{}",
className, methodName,
System.currentTimeMillis() - startTime,
e.getMessage(), e);
throw e;
}
}
}
使用注解
Java
@Service
public class OrderService {
@LogRecord(module = "订单", operation = "创建订单")
public Order createOrder(OrderDTO dto) {
// 业务逻辑
}
}
权限校验注解
Java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequirePermission {
String[] value();
Logical logical() default Logical.AND;
}
public enum Logical {
AND, OR
}
@Aspect
@Component
public class PermissionAspect {
@Autowired
private SecurityService securityService;
@Before("@annotation(requirePermission)")
public void checkPermission(RequirePermission requirePermission) {
String[] permissions = requirePermission.value();
boolean hasPermission;
if (requirePermission.logical() == Logical.AND) {
hasPermission = securityService.hasAllPermissions(permissions);
} else {
hasPermission = securityService.hasAnyPermission(permissions);
}
if (!hasPermission) {
throw new AccessDeniedException("权限不足");
}
}
}
// 使用
@RequirePermission(value = {"user:read", "user:write"}, logical = Logical.OR)
public void updateUser(User user) {
// 业务逻辑
}
性能监控注解
Java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PerformanceMonitor {
long threshold() default 1000; // 阈值ms
}
@Aspect
@Component
public class PerformanceAspect {
@Autowired
private MeterRegistry meterRegistry;
@Around("@annotation(monitor)")
public Object monitor(ProceedingJoinPoint joinPoint,
PerformanceMonitor monitor) throws Throwable {
long start = System.currentTimeMillis();
try {
return joinPoint.proceed();
} finally {
long duration = System.currentTimeMillis() - start;
// 记录指标
Timer.builder("method.execution")
.tag("class", joinPoint.getTarget().getClass().getSimpleName())
.tag("method", joinPoint.getSignature().getName())
.register(meterRegistry)
.record(duration, TimeUnit.MILLISECONDS);
// 超时告警
if (duration > monitor.threshold()) {
log.warn("方法执行超时: {}.{} 耗时:{}ms",
joinPoint.getTarget().getClass().getSimpleName(),
joinPoint.getSignature().getName(),
duration);
}
}
}
}
重试注解
Java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Retry {
int maxAttempts() default 3;
long delay() default 1000;
Class<? extends Exception>[] retryFor() default {Exception.class};
}
@Aspect
@Component
public class RetryAspect {
@Around("@annotation(retry)")
public Object retry(ProceedingJoinPoint joinPoint,
Retry retry) throws Throwable {
int attempts = 0;
Exception lastException;
while (attempts < retry.maxAttempts()) {
try {
return joinPoint.proceed();
} catch (Exception e) {
lastException = e;
attempts++;
if (!shouldRetry(e, retry.retryFor())) {
throw e;
}
if (attempts < retry.maxAttempts()) {
Thread.sleep(retry.delay());
log.warn("重试第{}次: {}", attempts, e.getMessage());
}
}
}
throw lastException;
}
private boolean shouldRetry(Exception e, Class<? extends Exception>[] retryFor) {
for (Class<? extends Exception> ex : retryFor) {
if (ex.isInstance(e)) {
return true;
}
}
return false;
}
}
注解继承处理
Java
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface Auditable {
String action();
}
// 切面处理类注解
@Around("@within(auditable) || @annotation(auditable)")
public Object audit(ProceedingJoinPoint joinPoint, Auditable auditable) {
// 处理逻辑
}
要点总结
- 注解定义需指定@Target和@Retention
- 切面使用@Around等通知类型拦截
- ProceedingJoinPoint获取方法上下文
- 合理设计注解属性提高灵活性
📝 发现内容有误?点击此处直接编辑