개발/Spring

[Spring 프로젝트] Annotation 동작 원리와 사용법

nova_dev 2020. 12. 7. 16:26
반응형

Annotation 동작 원리와 사용법

Spring Boot를 사용하다 보면 @Component, @Controller, @Repository, @Transactional, @Aspect 등 다양한 어노테이션을 사용하게 된다.
그럼 이런 어노테이션이 실제로는 어떻게 동작하는 것인지, 내가 만약 새로운 어노테이션을 만들어서 사용하고 싶다면 어떻게 하면 되는 것인지에 대해 알아보자.

1. Annotation 이란?

우선 어노테이션 자체는 주석과도 같다. (실제로 번역기를 돌려도 주석으로 나온다.) 즉, 코드 사이에 주석처럼 쓰이면서 특별한 의미, 기능을 수행하도록 하는 기술로 프로그램에게 추가적인 정보를 제공해주는 메타 데이터이다.

2. 어노테이션의 용도

  1. 컴파일러에게 코드 작성 문법 에러를 체크하도록 정보를 제공한다.
  2. 소프트웨어 개발툴이 빌드나 배치 시 코드를 자동으로 생성할 수 있도록 정보를 제공한다.
  3. 런타임 시 특정 기능을 실행하도록 정보를 제공한다.

Spring에서 제공되는 대부분의 Annotation은 3번, 런타임 시 특정 기능을 실행하도록 정보를 제공하는 용도로 사용되고 있다.

3. 어노테이션 파일 정의하기

@Target({ElementType.[적용대상]})
@Retention(RetentionPolicy.[정보유지되는 대상])
public @interface [어노테이션 이름]{
    ...
}

어노테이션 파일을 정의하는데 필요한 것은 총 세 가지다.
(1) Target (어노테이션의 적용 대상)
(2) Retention (어노테이션이 유지되는 대상)
(3) Annotation Name (class가 아닌 @interface로 정의된 어노테이션 이름)

아래에서는, 그럼 Type과 Retention 값을 어떻게 설정해야 하는지에 대해 설명한다.

  • Target 설정하기
    java8 document에서는 @Target에 들어가는 ElementType의 Enum값을 아래와 같이 정의하고 있다.
ElementType Enum 값
ANNOTATION_TYPE 어노테이션 선언
CONSTRUCTOR 생성자 선언
FIELD 필드 선언 (열거 형 상수 포함)
LOCAL_VARIABLE 지역 변수 선언
METHOD 메서드 선언
PACKAGE 패키지 선언
PARAMETER public parameter
TYPE 클래스, 인터페이스 (주석 유형 포함) 또는 열거 형 선언
TYPE_PARAMETER Type 파라미터 선언 (Java 8에 추가)
TYPE_USE Type이 사용되는 곳 (Java 8에 추가)
  • Retention 설정하기
    java8 document에서는 @Retention에 들어가는 ElementType의 Enum값을 아래와 같이 정의하고 있다.
RetentionPolicy Enum 값
CLASS 컴파일러에 의해 클래스 파일에 기록되지만 런타임에는 유지되지 않는다.
RUNTIME 컴파일러에 의해 클래스 파일에 기록되고 런타임에 유지된다.
SOURCE 소스에만 반영되어 컴파일러에 의해 삭제된다.

4. Spring @Controller 어노테이션 분석

위 내용을 토대로 우리가 Spring을 사용할 때 쓰는 Controller.class 파일을 분석해보자.

Controller.class 파일

우선 @Target은 ElementType.TYPE으로 정의되어, 우리가 흔히 Controller 클래스 파일을 만들었을 때, 해당 클래스에 어노테이션을 붙일 수 있게 해두었다.
그리고 Retention은 런타임 시에도 유지되어야 하므로 RetentionPolicy.RUNTIME으로 작성해 둔 것을 볼 수 있다.

참고사항으로, @Documented는 JavaDoc을 사용할 경우 해당 JavaDoc에 자동으로 Document를 남겨주는 어노테이션으로 알고 있다.

그리고 Controller에서 @Component 어노테이션을 붙이고, @AliasFor로 Component.class인 척 주석 속성에 별칭을 Component로 써두었다. (이 부분은 ComponentScan에서 Controller도 Component로 인식하게 하기 위해 붙여둔 것 같다. 마찬가지로 Configuration파일들이나 Repository도 동일하게 붙여있는 것을 확인했다.)

위와 같이 우리는 어노테이션 파일을 정의할 수 있다.
이 파일까지만 만들면, 우리는 우리가 정의한 새로운 어노테이션을 만들 수 있다.

5. 어노테이션 만들기 실습

다음으로는 실제로 우리가 어노테이션을 만들고, 사용하는 것을 연습해보자. (이 부분은 인프런 백기선 강사님의 실습과 동일하므로 자세한 설명과 함께 보고 싶다면 아래 참고자료를 확인하자.)

먼저 우리는 @LogExecutionTime 어노테이션을 만들어서 이 어노테이션을 붙인 메서드의 실행 시간을 알아보려 한다.

1. 어노테이션 파일 만들기

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 LogExecutionTime {

}

2. LogAspect 파일 만들기
이 단계에서는, @LogExecutionTime 어노테이션을 달아둔 메서드가 실행된 시간을 로그로 남기는 Aspect 파일을 작성한다.

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

@Component
@Aspect
public class LogAspect {

    Logger logger = LoggerFactory.getLogger(LogAspect.class);
    @Around("@annotation(LogExecutionTime)")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable{
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        Object ret = joinPoint.proceed();
        stopWatch.stop();
        logger.info(stopWatch.prettyPrint());
        return ret;
    }
}

3. 메서드에 @LogExecutionTime 어노테이션 붙여주기

 @LogExecutionTime
 @GetMapping("/owners/find")
 public String initFindForm(Map<String, Object> model) {
     model.put("owner", new Owner());
     return "owners/findOwners";
 }

4. 실행 결과 확인하기

---------------------------------------------
ns         %     Task name
---------------------------------------------
129860800  100%  

이와 같이 Annotation을 정의하고, AOP를 통해 만든 어노테이션의 로그를 찍어보는 것을 해보았다. 만약 어노테이션 생성까지만 하고 싶다면 맨 위 파일만 생성한다면 해당 어노테이션을 만들 수 있으니 참고하자.

AOP가 어떤 것인지 잘 모른다면 아래 이전에 정리해둔 블로그를 참고하자.
Spring AOP 로거 개발 가이드

6. 참고자료

해당 문서는 아래와 같은 자료를 참고하여 작성되었습니다.
저작권 관련 문제가 있다면 연락 부탁드립니다.

반응형