Annotaion

2023. 6. 18. 18:44Spring

아시다 싶이

Spring은 Annotation을 기반으로 운영되는 프레임 워크입니다.

@Component, @Controller, @Repository, @Transactional, @Aspect 등 다양한 어노테이션이 있습니다.

 

그렇다면 Annotation이란?

어노테이션은 주석과 비슷합니다. 실제로 컴파일러를 돌려도 주석으로 나오게 됩니다. 

즉, 코드 사이에 주석처럼 쓰이면서 특별한 의미, 기능을 수행하도록 하는 기술로써 프로그램에게 추가적인 정보를 제공해주는

일종의 메타 데이터입니다.

 

어노테이션은 활용 용도는 다음과 같습니다.

1) 컴파일러에게 문법 에러를 체크하도록 정보를 제공합니다.

2) IDE가 빌드나 매치 시 코드를 자동으로 생성할 수 있도록 정보를 재공합니다.

3) 런타임 시 특정 기능을 실행하도록 정보를 제공합니다.

Spring에서 제공되는 대부분의 어노테이션은 3번, 런타임 시 특정 기능을 실행하도록 정보를 제공하는데 사용되고 있습니다.

 

어노테이션을 정의하는데 필요한 것은 총 세가지 입니다.

1) Target

- 어노테이션의 적용 대상

 

Target에서 적용할 수 있는 열거형 상수

- ANNOTATION_TYPE: 어노테이션 선언

- CONSTRUCTOR: 생성자 선언

- FIELD: 필드 선언(열거형 상수 포함)

- LOCAL_VARIABLE: 지역 변수 선언

- METHOD: 메소드 선언

- PACKAGE: 패키지 선언

- PARAMETER: public parameter

- TYPE: 클래스, 인터페이스(주석 유형 포함) 또는 열거형 선언

- TYPE_PARAMETER: Type 파라미터 선언

- TYPE_USE: Type이 사용되는곳

 

2) Retention 

- 어노테이션이 유지되는 대상

 

Retention에서 적용할 수 있는 열거형 상수

- CLASS: 컴파일러에 의해 클래스파일에 기록되지만 런타임에는 유지되지 않는다.

- RUNTIME: 컴파일러에 의해 클래스 파일에 기록되고 런타임에 유지된다.

- SOURCE: 소스에만 반영되고 컴파일러에 의해 삭제된다.

 

3) Annotation Name

- 클래스가 아닌 @interface로 정의된 이름

 

그렇다면 우리가 가장 많이 사용하는 어노테이션중 하나인 @Controller 어노테이션에 대하여 분석해보겠습니다.

 

어노테이션 분석 ( RequestMapping )

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping

Target은 TYPE과 METHOD로 정의되어 있어, 클래스 파일과 메소드 모두 읽을수 있도록 하였습니다.

이 때문에 CLASS와 METHOD 모두 어노테이션을 적용할 수 있었습니다.

런타임시에도 어노테이션이 유지될수 있도록 Retention은 RUNTIME으로 되어있는것을 볼 수 있습니다.

참고로 @Documented는 JavaDoc에 자동으로 Document를 남겨주는 어노테이션 입니다.

@Mapping 어노테이션은 스프링에서 URL을 매핑하기 위해 사용되고 있습니다.

 

이번엔 직접 어노테이션을 만들고 사용해보도록 하겠습니다.

 

어노테이션 활용

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExecutionLog {

}

 응답시간을 로깅하기 위한 어노테이션을 만들었습니다.

특정 API의 응답시간을 파악하기 위해 메소드에 어노테이션이 적용될 수 있도록

Target은 METHOD로 지정합니다.

그 후 런타임 환경에서도 적용될 수 있도록 Rentention은 RUNTIME으로 설정하였습니다.

 

그 후 AOP를 적용하기 위하여 Aspect 클래스를 하나 생성합니다.

 

@Component
@Aspect
@Slf4j
public class LogAspect {

    @Around("@annotation(ExecutionLog)")
    public Object logging(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object ret = joinPoint.proceed();
        long responseTime = System.currentTimeMillis() - startTime;
        log.info("execution time {}", responseTime);
        return ret;
    }
}

Around로 ExecutionLog 어노테이션이 붙어있는 메소드들에 대해서 실행하도록 하고 reponseTime을 체크합니다.

 

@ExecutionLog
@GetMapping("/search")
@ApiOperation(value = "게시글 검색",
        notes = "게시글을 검색 할 수 있으며 keyword 하나로 제목, 내용을 모두 검색합니다.\n" +
                "JWT가 있어야 차단사용자 필터링이 가능합니다.")
public Page<BoardDto> search(@RequestParam(required = false) String keyword,
                             @PageableDefault(size = 24, sort = "createdAt") Pageable pageable) {
    Account account = AccountHolder.get();
    List<String> blockUsers = new ArrayList<>();
    String accountUuid = null;
    if (account != null) {
        blockUsers = account.getBlockStr();
        accountUuid = account.getUuid();
    }
    return service.search(blockUsers, keyword, pageable,accountUuid);
}

 

실제로 적용해보니 정상적으로 동작하는 것을 확인할 수 있습니다.

 

그럼 스프링에서 자주 활용되는 어노테이션을 알아보겠습니다.

 

스프링에서 활용되는 어노테이션

@Repository

- Data Access Layer의 클래스에 사용됩니다.

- DataAccessException 자동변환과 같은 AOP 적용 대상을 선정하기 위해 사용됩니다.

 

@Service

- Service Layer 클래스에 사용됩니다.

 

@Controller

- Persentation Layer의 MVC Controller에서 사용됩니다.

- 웹 서블릿에 의해 웹 요청을 처리하는 컨트롤러로 빈으로 선정됩니다.

 

@Component

- 위 레이어들의 구분을 적용하기 어렵지만 Bean에 등록하기 위해 사용됩니다.

 

이렇게 빈 등록을 위한 어노테이션이 여러개인 이유는 계층별로 빈의 특성과 종류를 구분하고 AOP에서 Pointcut 표현식을 사용하면 특정 Annotation이 달린 클래스만 설정이 가능하도록 되어 있기 때문입니다. 이를 통하여 특정 계층에 대하여 빈에 대해 부가 기능을 부여할 수 있습니다.

 

@Resource

- 자바에서 지원하는 어노테이션으로 의존성 주입에 활용됩니다

 

@Autowired

- 스프링에서 지원하는 어노테이션으로 의존성 주입에 활용되게 됩니다.

 

@Inject

- @Autowired가 스프링 프레임 워크에 종속되어있는 어노테이션이기 때문에 특정 프레임워크에 종속되지 않은 어플리케이션을 구성하기 위해 사용되는 의존성 주입 어노테이션 입니다.

 

@Controller

- 컨트롤러에 등록하여 Client의 요청 및 HandlerMaping을 하는데 활용됩니다.

 

@RequestMapping, GetMapping, PostMapping, .... 등등

- 요청 URL에 대한 정보를 설정하게 됩니다.

- Controller method의 메소드를 한정하고 같은 URL 요청에 대하여 HTTP method에 따라 서로 다른 메소드로 매핑할 수 있습니다.

- 클래스단에도 설정 가능하며 클래스에 설정시에 하위 메소드들에 대하여 URL들이 모두 적용디게 됩니다.

 

@PathVariable

- URL에서 템플릿 변수에 접근할때 활용됩니다.

 

@RequestParam

- 쿼리파라미터에 대하여 매핑할때 활용됩니다.

 

@RequestHeader

- HTTP 요청 헤더에 대한 값을 매핑할때 활용됩니다.

 

@CookieValue 

- HTTP의 쿠키에 대하여 매핑할때 활용됩니다.

 

@RequestBody

- HTTP 요청의 body 내용에 접근할때 활용됩니다.

 

@ResponseBody

- 리턴 객체 자체를 HTTP 응답으로 전송하기 위해 활용됩니다. ( 보통 JSON으로 리턴합니다.)

 

@ModelAttribute

- Model 데이터를 처리 할 수 있도록 활용되는 어노테이션입니다.

- Validation 체크를 하거나 모델 바인딩하거나 뷰단으로 데이터를 전송하는 어노테이션입니다.

 

@RestController

- 컨트롤러가 REST API 방식을 처리하기 위한 어노테이션입니다.

- 클래스단에 적용하게 되면 이하 API들이 @ResponseBody를 적용하지 않아도 JSON을 리턴할 수 있도록 되어 있습니다.

 

@CrossOrigin

- Ajax의 크로스 도메인 문제를 해결합니다.

 

@Valid

- 자바에서 지원하는 어노테이션으로 Validation에 활용됩니다.

 

@Validated

- 스프링에서 지원하는 어노테이션으로 Validation에 활용됩니다.

 

 

참고로 어노테이션들에는 옵션을 추가할 수 있기에 새로운 어노테이션을 발견하게 되면

적용 범위 부터, 옵션들 까지 한번씩 확인해볼 필요가 있습니다.

'Spring' 카테고리의 다른 글

Spring 에서 전략패턴 적용해보기  (1) 2024.04.14
Spring의 Event  (0) 2024.03.31
Servlet과 PSA  (0) 2023.05.29
스프링의 3대 핵심 요소  (0) 2023.05.21
Spring 그 시작과 핵심  (0) 2023.04.30