팀 프로젝트의 Spring 이관 작업을 진행하면서, 지속적으로 사용해야 하는 Cookie 정보를 가져오기 위해 request와 response를 매번 받아와야 하는 방식에 대해 고민하게 되었다. 이 접근 방식이 적절한지 궁금해지던 중, 커스텀 어노테이션에 대한 개념을 알게 되었다.
기본적으로 제공되는 어노테이션 외에도, 필요에 따라 자신만의 커스텀 어노테이션을 정의할 수 있다.
커스텀 어노테이션이란, 말 그대로 내가 어노테이션을 직접 만들어 사용할 수 있는 어노테이션을 말한다.
이번 포스팅에서는 커스텀 어노테이션을 만드는 방법과 그 사용 예시, 장단점에 대해 알아보겠다.
커스텀 어노테이션 정의
커스텀 어노테이션을 정의하려면, @interface 키워드를 사용하여 새로운 어노테이션 타입을 만들어야 한다. 아래는 @LoginCheck라는 커스텀 어노테이션의 예시이다.
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 LoginCheck {
String value() default "user"; // 기본값 설정
}
위의 코드에서 @Target은 이 어노테이션이 적용될 수 있는 대상을 지정하고, @Retention은 어노테이션이 유지되는 범위를 설정한다.
RUNTIME으로 설정했기 때문에, 런타임 중에 이 어노테이션을 사용할 수 있다.
AOP와 커스텀 어노테이션
자바에서 커스텀 어노테이션을 정의하는 것 외에도, AOP를 활용하여 이 어노테이션에 기능을 추가할 수 있다. AOP는 비즈니스 로직과 공통 관심사를 분리하여 코드의 재사용성을 높이고 유지보수성을 개선하는 데 도움을 준다.
아래는 @LoginCheck 어노테이션을 사용하는 AOP의 예시 코드인 LoginAspect 클래스이다.
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
@Aspect
@Component
public class LoginAspect {
@Around("@annotation(LoginCheck의 경로.LoginCheck)") // @LoginCheck 어노테이션이 붙은 메서드에 적용
public Object checkLogin(ProceedingJoinPoint joinPoint) throws Throwable {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getResponse();
HttpSession session = request.getSession();
// 로그인 정보 확인
String[] loginInfo = checkLoginInformation(request, response, session);
if (loginInfo[0] == null) {
// 로그인되지 않은 경우 로그인 페이지로 리다이렉트
return "redirect:login.do";
}
// 로그인된 경우 원래 메서드를 실행
return joinPoint.proceed();
}
private String[] checkLoginInformation(HttpServletRequest request, HttpServletResponse response, HttpSession session) {
String[] loginInformation = new String[2]; // [MEMBER_ID, CREW_CHECK]
// 쿠키에서 로그인 정보 가져오기
Cookie[] cookies = request.getCookies();
// 이하 생략
위의 LoginAspect 클래스는 @LoginCheck 어노테이션이 붙은 메서드에 대해 로그인 정보를 확인하고, 로그인되지 않은 경우에는 로그인 페이지로 리다이렉트하는 기능을 제공한다.
+ xml에 주입도 해놓아야 한다.
<!-- logincheck 주입 -->
<bean id="loginAspect" class="***class 경로***.LoginAspect">
<constructor-arg ref="loginCheck" />
</bean>
위처럼 사전작업을 하면, 내가 직접 만든 커스텀 어노테이션을 사용할 수 있다.
@LoginCheck
@PostMapping("/myPage.do")
public String myPage(MemberDTO memberDTO, BoardDTO boardDTO,ReservationDTO reservationDTO, Model model, HttpSession session) {
// 로그인된 사용자의 마이 페이지 처리
사용 시 장점
모듈화: 사용 시 관련된 기능을 모듈화할 수 있어, 각 모듈을 독립적으로 개발하고 테스트할 수 있다.
강력한 구조화: 어노테이션을 통해 특정한 비즈니스 로직을 명확하게 구조화할 수 있어, 팀원 간의 코드 이해도가 높아진다.
런타임 시 동적 기능 추가: AOP를 통해 코드 변경 없이 기존 코드에 새로운 기능을 동적으로 추가할 수 있다.
일관성: 특정 비즈니스 규칙을 어노테이션으로 정의하면, 코드 전체에서 일관되게 적용할 수 있어 개발 규칙이 명확해진다.
단점
가시성 감소: AOP를 사용하면 코드 흐름이 분산되어, 메서드의 동작 방식이 명확하지 않을 수 있다. 디버깅 시 실제 코드와 동작이 다를 수 있어 가독성이 떨어질 수 있다.
제한된 타입 검사: 커스텀 어노테이션의 경우, 어노테이션을 사용하는 메서드에서 기대하는 타입의 파라미터를 보장할 수 없어, 런타임 시 오류가 발생할 가능성이 있다.
복잡성 증가: AOP를 처음 접하는 개발자에게는 개념이 복잡하게 느껴질 수 있으며, 이를 이해하고 활용하는 데 추가적인 학습이 필요할 수 있다.
구현의 제약: AOP는 Java의 다중 상속을 지원하지 않기 때문에, 인터페이스를 통해 기능을 정의해야 하며, 이로 인해 설계가 복잡해질 수 있다.
커스텀 어노테이션과 AOP는 여러 장점과 단점을 가지고 있어, 프로젝트의 요구 사항과 팀의 개발 스타일에 따라 적절하게 활용하는 것이 중요하다.,,!
'Spring' 카테고리의 다른 글
[Spring] 쿠키 활용하기 - 자동 로그인 (0) | 2024.10.25 |
---|---|
[Spring] Multipart & 파일 업로드 (1) | 2024.10.23 |
[Spring] AOP와 어노테이션 (0) | 2024.10.16 |
[Spring] AOP 관점지향 프로그래밍 (1) | 2024.10.15 |
[Spring] Ajax를 이용한 비동기 처리와 아이디 중복검사 구현 (0) | 2024.10.14 |