一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

Spring Boot自定义注解:实战案例解析指南

时间:2026-05-25 14:00:01 编辑:袖梨 来源:一聚教程网

自定义注解是Java开发中提升代码效率的利器,通过AOP技术实现功能扩展,让业务逻辑更加清晰。本文将通过5个实战案例详细解析其实现方法。

Spring Boot 自定义注解实战案例详解

自定义注解作为元编程的重要工具,能够在保持原有代码结构的前提下,为程序添加额外功能。结合AOP技术使用,可以显著提升代码的可读性和可维护性。

自定义注解有哪些优势?

  1. 代码复用

    :将通用功能封装到注解中
  2. 业务解耦

    :分离核心业务与辅助功能
  3. 声明式编程

    :通过注解配置行为更直观
  4. 维护便捷

    :统一管理通用逻辑

自定义注解的原理

Spring Boot框架中,自定义注解的实现基于以下核心机制:

  1. Java注解机制

    (通过@interface定义)
  2. AOP技术或拦截器配合反射解析
  3. Spring容器

    的运行时自动处理

自定义注解的实现步骤

引入依赖

项目配置文件中需要添加必要的依赖项:


    
        org.springframework.boot
        spring-boot-starter-aop
    
    
        org.springframework.boot
        spring-boot-starter-web
    

定义自定义注解

基础注解定义示例:

import java.lang.annotation.*;
@Target(ElementType.METHOD) // 注解作用目标:方法
@Retention(RetentionPolicy.RUNTIME) // 运行时生效
@Documented
public @interface MyAnnotation {
    String value() default "default";
}

核心元注解说明:

@Target:指定作用范围

@Retention:确定生命周期

@Documented:包含在文档中

常见的自定义注解案例

❶ 自定义日志注解

定义注解

实现自动记录方法调用信息的功能

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodLog {
    String value() default "";
    boolean printArgs() default true;
    boolean printResult() default true;
    boolean timing() default true;
}

切面实现

日志记录的核心处理逻辑

@Aspect
@Component
@Slf4j
public class MethodLogAspect {
    @Around("@annotation(methodLog)")
    public Object around(ProceedingJoinPoint joinPoint, MethodLog methodLog) throws Throwable {
        String methodName = getMethodName(joinPoint);
        String className = joinPoint.getTarget().getClass().getSimpleName();
        long startTime = System.currentTimeMillis();
        if (methodLog.printArgs()) {
            Object[] args = joinPoint.getArgs();
            log.info("[{}#{}] 方法调用, 参数: {}", className, methodName, Arrays.toString(args));
        }
        try {
            Object result = joinPoint.proceed();
            if (methodLog.printResult()) {
                log.info("[{}#{}] 方法返回: {}", className, methodName, result);
            }
            if (methodLog.timing()) {
                long cost = System.currentTimeMillis() - startTime;
                log.info("[{}#{}] 方法执行耗时: {}ms", className, methodName, cost);
            }
            return result;
        } catch (Exception e) {
            log.error("[{}#{}] 方法执行异常: {}", className, methodName, e.getMessage());
            throw e;
        }
    }
    private String getMethodName(ProceedingJoinPoint joinPoint) {
        return joinPoint.getSignature().getName();
    }
}

使用示例

在控制器方法上应用日志注解

@RestController
@RequestMapping("/api/user")
public class UserController {
    @PostMapping
    @MethodLog(value = "创建用户", printArgs = true, printResult = true, timing = true)
    public User createUser(@RequestBody User user) {
        return userService.save(user);
    }
}

❷ 自定义参数校验注解

扩展标准校验功能,实现特定业务规则的验证

定义注解

手机号格式校验注解

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PhoneValidator.class)
public @interface Phone {
    String message() default "手机号格式错误";
    Class[] groups() default {};
    Class[] payload() default {};
}

实现校验器

校验逻辑的具体实现

public class PhoneValidator implements ConstraintValidator {
    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        return value != null && value.matches("^1[3-9]d{9}$");
    }
}

使用示例

在DTO字段上应用校验

@RestController
public class RegisterController {
    @PostMapping("/register")
    public String register(@Valid @RequestBody UserDTO userDTO) {
        return "注册成功";
    }
    public static class UserDTO {
        @Phone
        private String phone;
    }
}

❸ 自定义权限校验注解

实现方法级别的权限控制

定义注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CheckPermission {
    String value();
}

实现 AOP 权限校验

@Aspect
@Component
public class PermissionAspect {
    @Before("@annotation(checkPermission)")
    public void check(JoinPoint joinPoint, CheckPermission checkPermission) {
        String requiredPermission = checkPermission.value();
        String userPermission = "USER";
        if (!userPermission.equals(requiredPermission)) {
            throw new RuntimeException("权限不足,缺少:" + requiredPermission);
        }
    }
}

使用示例

@RestController
public class AdminController {
    @CheckPermission("ADMIN")
    @GetMapping("/admin")
    public String adminPage() {
        return "管理员页面";
    }
}

❹ 自定义分布式限流注解

定义注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RateLimit {
    String key() default "";
    int limit() default 100;
    int timeWindow() default 60;
    String message() default "访问过于频繁,请稍后再试";
}

切面实现

@Aspect
@Component
@Slf4j
public class RateLimitAspect {
    private final Map limiterMap = new ConcurrentHashMap<>();
    @Before("@annotation(rateLimit)")
    public void rateLimitCheck(RateLimit rateLimit) {
        String key = generateKey(rateLimit);
        RateLimiter limiter = limiterMap.computeIfAbsent(key, 
            k -> RateLimiter.create(rateLimit.limit() / (double) rateLimit.timeWindow()));
        if (!limiter.tryAcquire()) {
            throw new RuntimeException(rateLimit.message());
        }
    }
    private String generateKey(RateLimit rateLimit) {
        String key = rateLimit.key();
        if (StringUtils.isEmpty(key                                        				                
                    
                

热门栏目