[LG CNS AM Inspire Camp 1기] SpringBoot (5) - Intercepter & AOP & WebMvcConfigurer 인터페이스

정성엽·2025년 2월 7일
0

LG CNS AM Inspire 1기

목록 보기
39/53

INTRO

이번 포스팅에서는 Interceptor와 AOP가 스프링부트에서 어떻게 사용되는지 간단하게 정리할 예정이다.

AOP 관련 개념은 이전에 Spring을 공부하면서 정리한 포스팅이 있기 때문에 간단하게 예제 코드를 작성해보는 식으로 살펴보자 👀


1. 인터셉서(Interceptor)란?

우선 시작하기에 앞서 Interceptor에 대해서 간단하게 정리해보자

이름에서도 알 수 있다시피 Interceptor는 무언가를 가로채는 역할을 수행한다.

즉, 스프링 프레임워크에서 특정 요청을 가로채고, 처리하기 위해 사용되는 도구이다.

주로 요청 전후에 공통된 작업을 실행하거나, 요청을 처리하는 컨트롤러로 가기 전에 요청을 변경 또는 검사할 때 사용한다

그렇다면 어떻게 사용할 수 있을까?

💡 Interceptor 설정

인터셉터를 설정하기 위해서는 HandlerInterceptor 인터페이스를 구현한 클래스를 생성해줘야 한다.

코드를 살펴보자

Sample Code

@Slf4j
public class LoggerInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.debug("************* START *************");
        log.debug(" Request URI \t" + request.getRequestURI());
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.debug("************* END *************");
    }
}

Interceptor의 동작을 살펴보기 위해 @Slf4j 를 사용하여 로그를 남겨보려고 한다.

코드에서도 알 수 있다시피 Interceptor를 생성하기 위해서는 HandlerInterceptor 의 3가지 메서드를 오버라이딩 해야하는데, 여기서 각 메서드는 다음과 같은 동작을 수행한다.

1. preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)

  • 컨트롤러가 호출되기 전에 실행
  • true를 반환하면 다음 인터셉터 또는 컨트롤러가 호출되고, false를 반환하면 요청 처리를 중단하게 된다.

2. postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)

  • 컨트롤러 실행 후, 결과를 뷰로 보내기 전에 수행 (즉, 모델 데이터가 뷰에 반영되기 이전)
  • ModelAndView 객체를 통해 뷰에 전달할 데이터 조작이 가능

3. afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception)

  • 뷰 렌더링 후 호출되는 것
  • 주로 리소스 정리, 로깅 등의 작업에 사용

컨트롤러 호출 시점을 기준으로 전후 작업에서 처리할 내용을 각 메서드에 정의하여 인터셉터를 사용할 수 있다.

💡 Interceptor 등록

다음으로 우리는 위에서 생성한 인터셉터를 어딘가에 등록해야 사용할 수 있다.

스프링 4.0 이상에서는 자바 기반 설정을 지원하기 때문에, WebMvcConfiguer 인터페이스를 상속받는 설정 클래스를 추가하면 된다.

코드를 작성하면 다음과 같다.

Sample Code

@Configuration
public class WebMVCConfiguration implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoggerInterceptor());
    }
}

Result View

보다시피 우리가 설정한 인터셉터에 의해 컨트롤러 실행 전후로 로그가 찍히는 모습을 볼 수 있다.


2. WebMvcConfigurer 인터페이스

위에서 우리는 인터셉터의 설정을 추가하기 위해 WebMvcConfigurer 인터페이스를 구현한 설정 파일을 사용했다.

그렇다면 WebMvcConfigurer 는 어떤 인터페이스이길래 우리는 설정을 여기에서 추가해야하는 걸까?

💡 WebMvcConfigurer 목적

WebMvcConfigurer는 Spring MVC를 설정하기 위한 인터페이스이다.

@EnableWebMvc 와 함께 사용되어 Spring MVC의 다양한 기능을 커스터마이징할 수 있다는 특징이 존재한다.

실제로 해당 인터페이스를 타고 들어가면 주석이 하나 달려있다.

그 내용은 @EnableWebMvc 어노테이션을 사용하며, 이는 default configuration을 커스터마이징할 수 있도록 해준다고 한다.

쭉 찾아보면 WebMvcConfigurer 인터페이스의 메서드를 살펴보면 다음과 같다.

Sample Code

public interface WebMvcConfigurer {
    // 인터셉터 설정
    void addInterceptors(InterceptorRegistry registry);
  
    // 정적 리소스 처리 설정
    void addResourceHandlers(ResourceHandlerRegistry registry);
 
    // CORS 설정
    void addCorsMappings(CorsRegistry registry);

    // 뷰 컨트롤러 설정
    void addViewControllers(ViewControllerRegistry registry);

    // 포맷터 설정
    void addFormatters(FormatterRegistry registry);
    ...
}

이처럼 WebMvcConfigurer는 다양한 default 설정에 관한 메서드를 가지고 있으며, 개발자는 이를 오버라이딩하여 커스터마이징할 수 있는 것이다!


3. SpringBoot에서 AOP

우선 스프링 부트에서 AOP를 사용하기 위해서는 의존성을 추가해줘야 한다.

의존성 추가
//https://mvnrepository.com/artifact/org.springframework/spring-aspects
implementation 'org.springframework:spring-aspects:6.2.2'

의존성을 추가하기 위해서는 Maven AOP라고 검색하면 최신 버전을 확인할 수 있으니 참고하자

사실 AOP는 이전에 스프링에서 정리한 AOP와 사용 방법은 동일하기 때문에, 필자가 작성한 코드만 간단하게 훑고 넘어가자

Sample Code

package com.Board.Board.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

// SpringBoot에서는 @EnableAspectJAutoProxy 어노테이션을 추가하지 않아도 자동으로 AOP 설정을 활성화
@Aspect
@Slf4j
@Component
public class LoggerAspect {
    // 모든 컨트롤러와 서비스와 매퍼에 있는 메서드에 대해서 적용하겠다.
    @Pointcut("execution(* com.Board.Board..controller.*Controller.*(..)) || " +
            "execution(* com.Board.Board..service.*ServiceImpl.*(..))) ||" +
            "execution(* com.Board.Board..mapper.*Mapper.*(..))")
    private void loggerTarget(){
    }

    @Around("loggerTarget()")
    public Object logPrinter(ProceedingJoinPoint joinPoint) throws Throwable {
        String type = "";
        String className = joinPoint.getSignature().getDeclaringTypeName();
        String methodName = joinPoint.getSignature().getName();

        if(className.contains("Controller")) {
            type = "[Controller]";
        } else if(className.contains("Service")) {
            type = "[Service]";
        } else if(className.contains("Mapper")) {
            type = "[Mapper]";
        }

        log.debug(type + " " + className + "." + methodName);
        return joinPoint.proceed();
    }
}

Spring과 동일하게 컴포넌트 스캔의 기본대상인 @Aspect 를 추가하여 AOP를 자동으로 스프링 컨테이너에 등록할 수 있다.

한가지 차이점은 SpringBoot에서는 @EnableAspectJAutoProxy 어노테이션을 사용하지 않아도 된다는 점이다.

필자는 모든 메서드에 대해서 포인트 컷을 설정해주고 클래스 네임에 따라 로그를 찍어주도록 코드를 작성했다.


4. Interceptor vs AOP

필자는 강의를 수강하면서 Interceptor와 AOP가 수행하는 역할이 엄청 비슷하다고 생각했다.

따라서, 각 기능은 어떤 차이점을 가지고 있는지 언제 사용해야하는지가 궁금했고 이 부분을 정리하면 다음과 같다.

우선 사진을 하나 살펴보자

사진과 같이 Client의 Request와 Response를 컨트롤러에서 작업하기 전에 접근할 수 있는 방법은 Filter, Interceptor, AOP 이렇게 3가지가 존재한다.

Filter는 추후 다룰 예정이며, 우선은 Interceptor와 AOP를 비교해보도록 하자

💡 AOP가 있는데 왜 Interceptor를 사용할까?

AOP는 비즈니스단의 메서드에서 조금 더 세밀하게 조정하고자하는 경우 사용한다.

Interceptor는 컨트롤러 요청의 전후에 공통 작업을 수행할 수 있으며, 필요한 경우 URL 패턴을 통해 적용 범위를 제한할 수 있다.

반면, AOP는 메서드 실행을 기준으로 동작하며, URL뿐만 아니라 메서드 이름, 파라미터, 어노테이션 등 더 다양한 방식으로 대상을 지정할 수 있다.

이전에 작성한 Sample Code를 살펴보면 다음과 같은 특징을 볼 수 있다.

AOP

  • JoinPoint, ProceedingJoinPoint를 매개변수로 사용

Interceptor

  • HttpServletRequeest, HttpServletResponse를 매개변수로 사용

인터셉터에서 특정 URL 패턴에 동작하도록 코드를 작성하면 다음과 같다.

Sample Code

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new LoggerInterceptor())
           .addPathPatterns("/**")          // 모든 URL에 적용
           .excludePathPatterns("/admin/**"); // 특정 URL 제외
}

이러한 차이점을 이해한다면 우리는 특정 작업 전후에 적절한 로직을 정의할 수 있을 것이다!


OUTRO

이번 포스팅에서는 SpringBoot에서 Interceptor를 사용하는 방법과 AOP와의 차이점, 그리고 WebMvcConfigurer에 대해서 간단하게 살펴봤다.

Filter에 대해서는 아직 설명하지 않았는데 이 부분은 Spring Security를 정리하면서 포스팅할 것 같다.

AOP가 컨트롤러에 더 가까이 붙어있는 만큼 더욱 세밀한 조정이 가능하다고 이해하면 될 것 같다 👊

profile
코린이

0개의 댓글

관련 채용 정보