티스토리 뷰
Q. 상황
인터셉터를 설정 클래스에서 url 형식으로 적용 메소드를 지정하는 것이 아닌 Custom Annotation 기반으로 원하는 메소드에 지정하여 가독성을 높이고자 하였습니다. 하지만 @Retention / @Documented / @Target의 기능을 제대로 이해하지 못하여 오류속에서 헤매고 있어 3개의 기능에 대해 알아보고자 하였습니다.
Q. 질문
@Retention / @Documented / @Target 은 어떤 역할을 할까?
A. 답변
meta-annotaiton ?
meta-annotation 은 다른 annation 에서도 사용되는 annotation 의 경우를 말하며 custom-annotation 을 생성할 때 주로 사용됩니다.
@Retention 어노테이션으로 어느 시점까지 어노테이션의 메모리를 가져갈 지 설정하고, @Target 어노테이션으로 필드, 메소드, 클래스, 파라미터 등 선언할 수 있는 타입을 설정하면 커스텀 어노테이션을 생성할 수 있습니다.
@Retention
커스텀 애노테이션의 생성에서 해당 애노테이션이 선언된 대상(@Target의 속성값)의 메모리를 언제까지
유지 할 것인지 결정하는 애노테이션. @Retention은 RetentionPolicy라는 enum타입값을 인자로 받아 해당 policy값으로 메모리 유지타임을 결정한다. (즉, 어노테이션의 Life Time을 지정할 수 있다.)
RetentionPolicy에는 3가지 정책이 있으며, 각각의 설명은 다음과 같습니다
1. RetentionPolicy.SOURCE :
javac(자바 컴파일러)가 자바코드를 컴파일할때 해당 애노테이션의 메모리를 버림 = 사실상 주석
2. RetentionPolicy.CLASS :
컴파일러가 해당 애노테이션의 메모리를 유지하여 컴파일하지만, 실질적으로 JVM이 바이트코드를 해석해서 동작하는 Runtime단계에선 해당 메모리를 버린다 = 클래스파일에는 코드가 존재한다.
3. RetentionPolicy.RUNTIME :
JVM이 실제 클래스의 자바 바이트코드를 해석해서 동작하는 Runtime단계에서 메모리가 유지되고, Runtime이 종료되면 메모리도 사라진다.
간단하게 설명한다면
1. Source
Compile이후로 삭제되는 형태
2. Class
바이트 코드 파일까지 어노테이션 정보를 유지한다.하지만 리플렉션을 이용해서 어노테이션 정보를 얻을 수는 없다.
3. Runtime
바이트 코드 파일까지 어노테이션 정보를 유지하면서 리플렉션을 이용해서 런타임시에 어노테이션 정보를 얻을 수 있다.
@Target
커스텀 애노테이션이 적용될 대상을 지정하는 애노테이션으로 선언할 수 있는 enum값은 아래와 같다.
ElementType.PACKAGE : 패키지 선언
ElementType.TYPE : 타입 선언
ElementType.ANNOTATION_TYPE : 어노테이션 타입 선언
ElementType.CONSTRUCTOR : 생성자 선언
ElementType.FIELD : 멤버 변수 선언
ElementType.LOCAL_VARIABLE : 지역 변수 선언
ElementType.METHOD : 메서드 선언
ElementType.PARAMETER : 전달인자 선언
ElementType.TYPE_PARAMETER : 전달인자 타입 선언
ElementType.TYPE_USE : 타입 선언
@Documented
@Documented 어노테이션이 지정된 대상의 JavaDoc 에 이 어노테이션의 존재를 표기하도록 지정.
Code (인터셉터)
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomAnnotationAuth {
}
제가 직접 만든 CustomAnnotationAuth입니다.
저는 @Retention(RetentionPolicy.CLASS로 처음에 선언하였습니다. 하지만 어노테이션 정보가 인터셉터 prehander에서 null값이 넘어오는 것을 확인하였고 @Retention(RetentionPolicy.RUNTIME으로 수정해 줌으로써 어노테이션 정보가 넘어오는 것을 확인할 수 있었습니다.
@CustomAnnotationAuth // 어노테이션 적용
@PutMapping("/update")
public void update(@Valid @RequestBody Member member,
BindingResult bindingResult,
HttpServletRequest request,HttpServletResponse response) throws IOException{
...
//회원정보 수정 메소드
}
제가 적용하고 싶은 메소드에 어노테이션을 선언함으로서 Custom Annotation을 적용할 수 있게 하였습니다.
@Slf4j
@RequiredArgsConstructor
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 어노테이션 적용 부분
AopAuth filter = handlerMethod.getMethod().getAnnotation(AopAuth.class);
AopAuth filter2 = handlerMethod.getMethodAnnotation(AopAuth.class);
System.out.println(handler);
System.out.println(filter);
System.out.println(filter2);
// 어노테이션 정보가 없다면 작동 x
// 어노테이션 정보가 있으면 작동 o
if (filter != null) {
return true;
}
return false;
}
}
인터셉터의 preHandler 부분에 어노테이션 정보를 받아 옴으로써 어노테이션 정보가 없다면 인터셉터에서 컨트롤러로 넘어가지 못하게 return false를 선언하였습니다.
지금까지의 코드는 인터셉터를 Custom Annotation을 이용해서 메소드에 직접 지정해 주기 위한 코드였습니다.
인터셉터의 어노테이션은 @Retention(RetentionPolicy.RUNTIME을 사용하였습니다.
다은은 AOP를 어노테이션 기반으로 사용하는 코드에 대해 살펴 보겠습니다.
Code (AOP)
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
public @interface AopAuth {
}
@RequiredArgsConstructor
@Aspect // AOP Aspect
@Component
public class LoginAuth {
@Around("@annotation(AopAuth)") // 어노테이션기반
public Object LoginAroundAuth(ProceedingJoinPoint pjp) throws Throwable {
HttpServletRequest request =((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
HttpSession session = request.getSession(false);
UserProfile updateUserProfile = (UserProfile) session.getAttribute("nowId");
Object reval = pjp.proceed();
return reval;
}
}
@CustomAnnotationAuth // 어노테이션 적용
@PutMapping("/update")
public void update(@Valid @RequestBody Member member,
BindingResult bindingResult,
HttpServletRequest request,HttpServletResponse response) throws IOException{
...
//회원정보 수정 메소드
}
AOP에는 @Retention(RetentionPolicy.CLASS을 사용하였습니다..
'질문 & 답변' 카테고리의 다른 글
트러블 슈팅 (feat. Eureka AWS 배포하기) (0) | 2021.10.08 |
---|---|
Agile pull requests (feat. PR관리방법) (0) | 2021.08.01 |
"DAO / Repository" 의 차이는 무엇일까? (0) | 2021.07.08 |
"Mapper / DAO" 의 차이점은 무엇일까? (0) | 2021.07.08 |
"AOP / 필터 / 인터셉터"는 어떤 차이가 있을 (0) | 2021.07.08 |