Spring Boot에서 애노테이션은 코드의 가독성을 높이고 반복 코드를 줄여주는 강력한 도구입니다. 특히, Custom Annotation(커스텀 애노테이션)을 활용하면 특정 로직을 재사용하거나 추상화할 수 있어, 코드의 유지보수성과 확장성을 극대화할 수 있습니다. 이 블로그에서는 Custom Annotation을 만들어 사용하는 방법을 설명하고, 실제 프로젝트 예시와 함께 어떻게 활용할 수 있는지 알아보겠습니다.
1. Custom Annotation을 사용하는 이유
- 중복 코드 제거: 반복되는 코드를 한 곳에 모아 커스텀 애노테이션으로 처리함으로써 코드의 중복을 줄일 수 있습니다.
- 비즈니스 로직 분리: 핵심 비즈니스 로직에서 부가적인 로직(로그 처리, 유효성 검사 등)을 분리하여 코드의 가독성을 높이고 유지보수가 쉬워집니다.
- 강한 결합도 감소: 특정 기능을 애노테이션으로 분리하면 여러 클래스에서 같은 기능을 재사용할 수 있고, 의존성을 줄일 수 있습니다.
- 데코레이터 패턴과 유사한 효과: 커스텀 애노테이션은 메서드나 클래스에 부가 기능을 추가하는 데 유용합니다. 예를 들어, 로깅, 트랜잭션 관리 등을 자동화할 수 있습니다.
2. 프로젝트 설정 (Gradle 기반)
Spring Boot 프로젝트에서 커스텀 애노테이션을 사용하려면 Spring AOP와 같은 의존성이 필요합니다. 이를 위해 Gradle에서 아래와 같은 설정을 추가합니다.
plugins {
id 'org.springframework.boot' version '3.1.0'
id 'io.spring.dependency-management' version '1.0.15.RELEASE'
id 'java'
}
group = 'com.example'
version = '1.0.0-SNAPSHOT'
sourceCompatibility = '17'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-aop'
implementation 'org.springframework.boot:spring-boot-starter'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
test {
useJUnitPlatform()
}
위 설정에서 spring-boot-starter-aop는 AOP(Aspect-Oriented Programming) 기반으로 커스텀 애노테이션을 처리할 때 필요합니다.
3. Custom Annotation 개발하기
3.1 커스텀 애노테이션 정의
간단한 예로 메서드 실행 시간을 측정하는 @ExecutionTime 애노테이션을 만들어보겠습니다.
package com.example.customannotation.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
// 애노테이션을 메서드에 적용하기 위해 ElementType.METHOD 사용
@Target(ElementType.METHOD)
// 런타임에 유지되어야 AOP에서 인식 가능하므로 RetentionPolicy.RUNTIME 지정
@Retention(RetentionPolicy.RUNTIME)
public @interface ExecutionTime {
}
3.2 애노테이션을 처리하는 Aspect 클래스 작성
Aspect 클래스를 작성하여 @ExecutionTime 애노테이션이 붙은 메서드의 실행 시간을 측정할 수 있습니다.
package com.example.customannotation.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class ExecutionTimeAspect {
@Around("@annotation(com.example.customannotation.annotation.ExecutionTime)")
public Object measureExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
Object proceed = joinPoint.proceed(); // 실제 메서드 실행
long endTime = System.currentTimeMillis();
System.out.println(joinPoint.getSignature() + " 실행 시간: " + (endTime - startTime) + "ms");
return proceed;
}
}
- @Aspect는 이 클래스가 AOP 기능을 제공하는 클래스임을 나타냅니다.
- @Around는 특정 애노테이션이 적용된 메서드의 실행 전후를 감싸서 처리하는데 사용됩니다. 여기서는 @ExecutionTime 애노테이션이 적용된 메서드를 감싸고 실행 시간을 측정합니다.
4. 애노테이션 적용 및 활용
이제 @ExecutionTime 애노테이션을 실제 메서드에 적용하여 어떻게 동작하는지 확인해보겠습니다.
package com.example.customannotation.service;
import com.example.customannotation.annotation.ExecutionTime;
import org.springframework.stereotype.Service;
@Service
public class SampleService {
@ExecutionTime
public void executeTask() throws InterruptedException {
// 예제: 2초 대기
Thread.sleep(2000);
System.out.println("작업 완료!");
}
}
4.1 애플리케이션 실행
package com.example.customannotation;
import com.example.customannotation.service.SampleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class CustomAnnotationApplication implements CommandLineRunner {
@Autowired
private SampleService sampleService;
public static void main(String[] args) {
SpringApplication.run(CustomAnnotationApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
sampleService.executeTask();
}
}
애플리케이션을 실행하면 executeTask 메서드의 실행 시간이 콘솔에 출력됩니다.
5. Custom Annotation을 활용한 확장
위 예제에서는 메서드의 실행 시간을 측정하는 단순한 기능을 구현했지만, Custom Annotation을 통해 할 수 있는 일은 무궁무진합니다. 다음과 같은 시나리오에서도 유용하게 사용될 수 있습니다.
- 로그 자동화: 특정 애노테이션을 붙인 메서드에 자동으로 로그를 남기는 로직을 구현.
- 트랜잭션 관리: 애노테이션을 통해 특정 메서드나 클래스의 트랜잭션 처리 로직을 자동으로 적용.
- 권한 검사: 메서드 호출 전에 사용자의 권한을 체크하고, 권한이 없으면 예외를 던지는 로직 추가.
Custom Annotation을 사용하면 코드의 가독성과 재사용성을 크게 높일 수 있습니다. 특히 AOP와 결합하여 부가적인 기능(로그, 트랜잭션, 권한 체크 등)을 애플리케이션의 핵심 비즈니스 로직에서 분리할 수 있습니다. 이로 인해 개발자는 비즈니스 로직에만 집중할 수 있고, 유지보수와 확장이 훨씬 수월해집니다.
'Spring' 카테고리의 다른 글
Spring Cloud Kubernetes로 클라우드 네이티브 애플리케이션 만들기: 주요 기능과 도입 장점 (0) | 2024.09.10 |
---|---|
Spring Boot 애플리케이션을 Kubernetes에 완벽하게 배포하는 방법: Helm과 Spring Cloud Kubernetes를 활용한 실전 가이드 (0) | 2024.09.10 |
Spring Boot AOT 컴파일: 성능 최적화의 새로운 패러다임 (0) | 2024.09.10 |
비동기 데이터베이스 혁신, Spring R2DBC로 고성능 애플리케이션 만들기 (0) | 2024.09.09 |
Spring WebFlux: 비동기 논블로킹으로 고성능 웹 애플리케이션 만들기 (0) | 2024.09.09 |