Custom Annotation 만들기

@Target({ElementType.TYPE, ElementType.METHOD}) 
@Retention(RetentionPolicy.RUNTIME)            
public @interface LogExecutionTime {
    String level() default "INFO";
    boolean trace() default false;
}
옵션 설명
@Target({ElementType.TYPE, ElementType.METHOD}) 클래스와 메서드에 모두 사용 가능
@Retention(RetentionPolicy.RUNTIME) 런타임에서도 유지 (AOP 활용을 위해 필수)
String level() Annotation 속성값 (기본값 제공 가능)
boolean trace() 옵션 처리용 boolean 속성

AOP 구현

@Aspect
@Component
public class LogExecutionTimeAspect {

    private static final Logger log = LoggerFactory.getLogger(LogExecutionTimeAspect.class);

    @Around("@annotation(logExecutionTime)")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint,
                                   LogExecutionTime logExecutionTime) throws Throwable {

        long start = System.currentTimeMillis();
        Object result = joinPoint.proceed();
        long end = System.currentTimeMillis();

        // Annotation의 속성값을 가져와 활용
        String level = logExecutionTime.level();
        boolean trace = logExecutionTime.trace();

        String message = "[%s] executed in %d ms".formatted(
                joinPoint.getSignature().toShortString(), (end - start)
        );

        if (trace) {
            message += " / args=" + Arrays.toString(joinPoint.getArgs());
        }

        switch (level.toUpperCase()) {
            case "DEBUG" -> log.debug(message);
            case "WARN"  -> log.warn(message);
            default      -> log.info(message);
        }

        return result;
    }
}

코드 의미
@Around("@annotation(logExecutionTime)") Annotation이 붙은 메서드만 감지
logExecutionTime.level() Annotation 속성 사용
joinPoint.getArgs() trace 옵션일 때만 파라미터 출력

Annotation 사용 예시

@Service
@LogExecutionTime(level = "INFO") // 클래스 전체 메서드에 공통 적용
public class UserService {

    @LogExecutionTime(level = "DEBUG", trace = true) // 메서드별 오버라이딩
    public void createUser() throws InterruptedException {
        Thread.sleep(200);
    }

    public void deleteUser() throws InterruptedException {
        Thread.sleep(100);
    }
}

실행 결과

UserService.createUser() executed in 202 ms / args=[]   (DEBUG)
UserService.deleteUser() executed in 101 ms             (INFO)

실무 사용 예시

Custom Annotation 실무 확장 예시
@CheckAuth(role = "ADMIN") 권한 체크 AOP
@DistributedLock(key = "#userId") Redis 분산 락
@ApiTrace(masking = true) 개인정보 마스킹 로그