안녕하세요! 이번 글에서는 Spring Boot 애플리케이션에서 자주 사용되는 세 가지 기술, Filter, Interceptor, 그리고 AOP의 개념과 사용법을 정리해 보려고 합니다. 이 기술들은 각각 요청 처리 과정의 특정 시점에 로직을 삽입하는 역할을 하지만, 적용되는 계층과 방식에 차이가 있습니다. 어떤 상황에서 어떤 기술을 사용해야 할지 명확히 이해하는 데 도움이 될 거예요. 😊
1. Filter (필터)
필터는 Servlet 영역에서 동작하며, 모든 요청이 컨트롤러에 도달하기 전에 공통적으로 처리해야 할 작업을 수행할 때 사용됩니다. 웹 애플리케이션의 가장 앞단에 위치하기 때문에, 여러 컨트롤러에 걸쳐 반복되는 로직을 구현하기에 적합합니다.
주요 용도
- 보안 및 인증: 로그인 여부 확인, JWT 토큰 유효성 검사
- 로깅: 모든 요청에 대한 로그 기록
- 인코딩: 문자 인코딩 설정
- XSS 방어: SQL 인젝션, XSS 공격 방어 로직
사용법
javax.servlet.Filter 인터페이스를 구현하여 필터를 정의합니다. doFilter() 메서드 내에 로직을 작성하고, chain.doFilter()를 호출하여 다음 필터나 서블릿으로 요청을 전달해야 합니다.
Java
import javax.servlet.*;
import java.io.IOException;
public class CustomFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 요청 처리 전 로직
System.out.println("Filter: 요청이 들어왔습니다.");
// 다음 필터로 요청 전달
chain.doFilter(request, response);
// 요청 처리 후 로직
System.out.println("Filter: 요청 처리가 완료되었습니다.");
}
}
필터를 등록하려면 @Component 어노테이션을 사용하거나, FilterRegistrationBean을 통해 수동으로 등록할 수 있습니다.
Java
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<CustomFilter> customFilter() {
FilterRegistrationBean<CustomFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new CustomFilter());
registrationBean.addUrlPatterns("/api/*"); // 필터를 적용할 URL 패턴
return registrationBean;
}
}
2. Interceptor (인터셉터)
인터셉터는 Spring MVC 영역에서 동작하며, Dispatcher Servlet이 컨트롤러를 호출하기 전후에 작업을 가로채는 역할을 합니다. HandlerInterceptor 인터페이스를 구현하며, 필터보다 더 세밀하게 요청을 제어할 수 있습니다.
주요 용도
- 로그인 체크: 특정 핸들러(컨트롤러) 실행 전 로그인 여부 확인
- 권한 체크: 특정 페이지나 기능에 대한 접근 권한 확인
- 성능 측정: 컨트롤러 실행 시간 측정
- API 호출 로깅: 특정 API에 대한 상세 로그 기록
사용법
HandlerInterceptor 인터페이스를 구현하고, preHandle(), postHandle(), afterCompletion() 메서드를 재정의하여 로직을 작성합니다.
preHandle(): 컨트롤러 실행 전 호출됩니다.true를 반환하면 다음 단계로 진행하고,false를 반환하면 요청 처리가 중단됩니다.postHandle(): 컨트롤러 실행 후 View 렌더링 직전에 호출됩니다.afterCompletion(): View 렌더링이 완료된 후, 요청 처리의 모든 과정이 끝난 뒤에 호출됩니다.
Java
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class CustomInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("Interceptor: 컨트롤러 실행 전");
return true; // 계속 진행
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("Interceptor: 컨트롤러 실행 후");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("Interceptor: View 렌더링 완료 후");
}
}
인터셉터는 WebMvcConfigurer를 구현한 설정 클래스에서 addInterceptors() 메서드를 오버라이드하여 등록합니다.
Java
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new CustomInterceptor())
.addPathPatterns("/api/**"); // 인터셉터를 적용할 URL 패턴
}
}
3. AOP (Aspect-Oriented Programming, 관점 지향 프로그래밍)
AOP는 **OOP(객체 지향 프로그래밍)**를 보완하는 개념으로, 애플리케이션의 여러 부분에 **흩어져 있는 공통 기능(횡단 관심사)**을 한 곳에 모아 관리하는 기술입니다. Spring AOP는 프록시 패턴을 기반으로 구현됩니다.
주요 용어
- Aspect (애스펙트): 횡단 관심사를 모듈화한 단위.
@Aspect어노테이션으로 정의합니다. - Join Point (조인 포인트): Advice가 적용될 수 있는 지점. 메서드 호출, 필드 접근 등이 있습니다.
- Pointcut (포인트컷): Join Point 중에서 실제로 Advice를 적용할 지점을 정의하는 표현식입니다.
- Advice (어드바이스): Join Point에서 실행되는 실제 코드.
@Before,@After,@Around등으로 정의합니다.
주요 용도
- 트랜잭션 관리:
@Transactional - 로깅: 메서드 실행 전후 로그 기록
- 성능 측정: 특정 메서드의 실행 시간 측정
- 예외 처리: 공통 예외 처리 로직
사용법
먼저 spring-boot-starter-aop 의존성을 추가합니다.
XML
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
@Aspect 어노테이션을 사용하여 Aspect를 정의합니다.
Java
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
// com.example.service 패키지 내 모든 public 메서드를 포인트컷으로 지정
@Pointcut("execution(public * com.example.service.*.*(..))")
private void serviceMethods() {}
// Before Advice: 메서드 실행 전
@Before("serviceMethods()")
public void beforeMethod() {
System.out.println("AOP: 메서드 실행 전");
}
// After Advice: 메서드 실행 후
@After("serviceMethods()")
public void afterMethod() {
System.out.println("AOP: 메서드 실행 후");
}
// Around Advice: 메서드 실행 전후에 모두 관여
@Around("serviceMethods()")
public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("AOP: Around - 메서드 실행 시작");
Object result = joinPoint.proceed(); // 실제 메서드 실행
System.out.println("AOP: Around - 메서드 실행 종료");
return result;
}
}
🎯 Filter vs Interceptor vs AOP, 언제 무엇을 써야 할까?

- 필터는 모든 웹 요청에 대해 공통적으로 적용해야 할 전역적인 기능(예: 보안, 인코딩)에 적합합니다.
- 인터셉터는 Spring MVC에 특화되어 있으며, 특정 URL 패턴에 따라 컨트롤러 실행 전후에 로직을 적용할 때 유용합니다.
- AOP는 핵심 비즈니스 로직과 분리된 횡단 관심사를 메서드 단위로 적용할 때 사용합니다.
@Transactional과 같은 선언적 트랜잭션 처리가 대표적인 예시입니다.