**스프링 부트 3(Spring Boot 3)**는 다양한 기능과 유연한 확장성을 제공하여 개발자가 효율적으로 애플리케이션을 개발할 수 있도록 돕습니다. 그중에서도 어노테이션(annotation)은 코드의 간결성과 가독성을 높이는 데 중요한 역할을 합니다.
특히, 상황에 맞는 커스텀 어노테이션을 만들면 공통 로직을 추상화하거나 복잡한 설정을 간단히 표현할 수 있어 코드의 재사용성을 극대화할 수 있습니다. 이 글에서는 스프링 부트 3에서 커스텀 어노테이션을 만드는 방법을 예제를 통해 상세히 설명하겠습니다.
1. 커스텀 어노테이션의 기본 구성
커스텀 어노테이션은 Java의 메타 어노테이션을 사용해 정의할 수 있습니다. 자주 사용하는 메타 어노테이션은 다음과 같습니다.
- @Target: 어노테이션을 적용할 수 있는 위치를 지정합니다. 예를 들어, 클래스, 메서드, 필드 등입니다.
- @Retention: 어노테이션의 유지 기간을 설정합니다. 주로 RUNTIME으로 설정하여 실행 시점에 어노테이션 정보를 참조합니다.
- @Documented: 어노테이션이 Javadoc에 포함되도록 설정합니다.
- @Inherited: 어노테이션이 하위 클래스에 상속되도록 지정합니다.
기본 예제: 간단한 커스텀 어노테이션
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD) // 메서드에 적용
@Retention(RetentionPolicy.RUNTIME) // 실행 시점 유지
public @interface MyCustomAnnotation {
String value() default "Default Value"; // 속성 정의
}
2. 커스텀 어노테이션 활용 사례
커스텀 어노테이션은 다양한 방식으로 활용됩니다. 아래에서 대표적인 세 가지 사례를 다뤄보겠습니다.
사례 1: 메서드 실행 시간을 로깅하는 어노테이션
많은 개발자는 특정 메서드의 실행 시간을 측정하고 로그로 남기고 싶어 합니다. 이를 커스텀 어노테이션으로 간단히 구현할 수 있습니다.
- 어노테이션 정의
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogExecutionTime {
}
- Aspect 구현
스프링의 AOP(Aspect-Oriented Programming)를 활용해 어노테이션이 적용된 메서드의 실행 시간을 로깅합니다.
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.ProceedingJoinPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LogExecutionTimeAspect {
private static final Logger logger = LoggerFactory.getLogger(LogExecutionTimeAspect.class);
@Around("@annotation(LogExecutionTime)")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object proceed = joinPoint.proceed();
long executionTime = System.currentTimeMillis() - start;
logger.info("{} executed in {} ms", joinPoint.getSignature(), executionTime);
return proceed;
}
}
- 사용 방법
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class SampleController {
@LogExecutionTime
@GetMapping("/sample")
public String sampleEndpoint() {
// 간단한 로직
return "Hello, World!";
}
}
사례 2: 사용자 권한 검사 어노테이션
특정 API에 접근할 때 사용자의 권한을 확인해야 하는 경우, 커스텀 어노테이션으로 로직을 캡슐화할 수 있습니다.
- 어노테이션 정의
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CheckRole {
String role();
}
- Aspect 구현
@Aspect
@Component
public class RoleCheckAspect {
@Around("@annotation(checkRole)")
public Object checkRole(ProceedingJoinPoint joinPoint, CheckRole checkRole) throws Throwable {
String requiredRole = checkRole.role();
// 사용자 권한 검증 로직 (예: SecurityContextHolder에서 권한 가져오기)
String userRole = "USER"; // 예제용 하드코딩
if (!userRole.equals(requiredRole)) {
throw new SecurityException("권한 부족: " + requiredRole);
}
return joinPoint.proceed();
}
}
- 사용 방법
@RestController
public class AdminController {
@CheckRole(role = "ADMIN")
@GetMapping("/admin")
public String adminEndpoint() {
return "Admin Access Granted!";
}
}
사례 3: DTO 유효성 검사 어노테이션
입력 데이터의 유효성을 검사할 때 스프링의 Validator와 연계하여 커스텀 어노테이션을 사용할 수 있습니다.
- 어노테이션 정의
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Constraint(validatedBy = CustomValidator.class)
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidName {
String message() default "Invalid name";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
- Validator 구현
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
public class CustomValidator implements ConstraintValidator<ValidName, String> {
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
return value != null && value.matches("^[a-zA-Z]+$");
}
}
- 사용 방법
public class UserDTO {
@ValidName
private String name;
// Other fields and methods...
}
3. 커스텀 어노테이션의 장점
- 코드 재사용성: 반복되는 로직을 추상화하여 재사용 가능.
- 가독성 향상: 코드가 더 간결하고 명확하게 표현됨.
- 확장성: 다양한 설정과 검증 로직을 손쉽게 추가 가능.
결론
스프링 부트 3에서 커스텀 어노테이션을 활용하면 공통 로직을 효율적으로 관리하고 코드의 유지보수성을 크게 향상시킬 수 있습니다. 이 글에서 설명한 세 가지 사례를 참고해 실제 프로젝트에 적합한 커스텀 어노테이션을 설계해 보세요. 이를 통해 더욱 효율적이고 직관적인 코드를 작성할 수 있을 것입니다.
'스프링 부트3' 카테고리의 다른 글
스프링 부트 3와 PostgreSQL 연결하기 (0) | 2024.12.05 |
---|---|
YAML 파일로 스프링 부트 3 설정 관리 (0) | 2024.12.05 |
HATEOAS를 이용한 RESTful 서비스 구현 (0) | 2024.12.05 |
스프링 부트 3와 GraphQL (0) | 2024.12.05 |
Swagger를 사용한 API 문서화 (0) | 2024.12.05 |