개발지식 먹는 하마 님의 블로그
공통 로직 처리를 위한 Filter, Interceptor 그리고 AOP 본문
로그인 관련 처리와 같이 공통으로 처리해야 하는 로직들이 있다.
이러한 공통 로직은 Filter, Interceptor, AOP를 활용하여 처리할 수 있다.
사용 범위는 제한적이지만 필수적으로 사용되는 요소들이다.
이 셋은 동작 시점, 목적, 사용 방식에서 차이가 있다.
Request가 들어올 때, Filter ➡️ Interceptor ➡️ AOP
Response가 나갈 때, AOP ➡️ Interceptor ➡️ Filter
Filter
Request, Response를 걸러서 전달한다.
- Servlet 기반, Dispatcher Servlet 이전에 동작한다.
- 클라이언트 → 서버로의 요청 전/후에 처리
- 여러 필터가 체인으로 연결되어 연속으로 수행될 수 있다.
- 인코딩 처리, 로깅, 보안 검사, 인증, CORS 등을 위해 사용한다.
💡 필터는 Request와 Response를 조작할 수 있지만, 인터셉터는 조작이 불가능하다.
Filter 구현 예시
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("MyFilter 초기화됨");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
System.out.println("MyFilter 실행: 요청 URI = " + httpRequest.getRequestURI());
// 다음 필터 또는 서블릿으로 요청 전달
chain.doFilter(request, response);
}
@Override
public void destroy() {
System.out.println("MyFilter 종료됨");
}
}
✅ implement Filter
필요한 필터를 구현하기 위해서는 먼저 Filter 인터페이스를 상속받아야 한다.
목적에 따라 기본 Filter에서 더 확장된 여러 Filter 확장 클래스들도 상속받을 수 있다.
목적 | Filter 확장 클래스 |
요청 당 한 번만 실행 | ⭐ OncePerRequestFilter |
UTF-8 설정 | CharacterEncodingFilter |
HTML 폼에서 DELETE/PUT 사용 | HiddenHttpMethodFilter |
PUT 요청에서 form 데이터 사용 | HttpPutFormContentFilter |
Spring Bean 필터 위임 | DelegatingFilterProxy |
정적 캐시 처리 | ShallowEtagHeaderFilter |
OncePerRequestFilter는 Spring 필터 구현 시 가장 많이 상속받는 필터이다.
Filter는 요청 1건에 대해서 여러 번 실행될 수 있는데 OncePerRequestFilter 요청 1건에 대해 1번만 실행되도록 보장한다.
✅ init, doFilter, destroy
- init() - 필터 인스턴스 초기화 시 실행되는 메서드
- doFilter() - 클라이언트의 요청/응답 처리 시 실행되는 메서드
- destroy() - 필터 인스턴스가 제거될 때 실행되는 메서드
✅ doFilter
doFilter()를 호출해야 다음 필터 또는 서블릿으로 넘어간다.
☑️ 등록 방법
@Component
@Component
public class MyFilter implements Filter
@Configuration + @Bean
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<MyFilter> loggingFilter() {
FilterRegistrationBean<MyFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new MyFilter());
registrationBean.addUrlPatterns("/api/*"); // 필터 적용 경로 설정
registrationBean.setOrder(1); // 필터 실행 순서 (낮을수록 먼저 실행)
return registrationBean;
}
}
Interceptor
Request, Response에 대한 작업을 하기 전에 가로채서 전/후 처리할 수 있도록 한다.
- Spring MVC 기반
- Controller에 도달하기 전에 검사 또는 기록한다.
- 인증/인가, 요청 로그 기록, 공통 헤더 처리, 요청 시간 측정 등
💡 스프링 MVC의 인터셉터 체인을 구성하여 여러 개의 인터셉터를 적용할 수 있다.
Interceptor 구현 예시
public class MyInterceptor implements HandlerInterceptor {
// 요청이 컨트롤러로 전달되기 전에 실행
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("Request Intercepted! - " + request.getRequestURI());
// true를 반환하면 컨트롤러로 요청이 전달됨
return true;
}
// 요청 처리 후, 뷰 렌더링 전에 실행
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, org.springframework.web.servlet.ModelAndView modelAndView) throws Exception {
System.out.println("Post Handle executed!");
}
// 요청 처리 후, 뷰 렌더링 후 실행
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("Request Completed!");
}
}
✅ 주요 메서드
- preHandle() - 컨트롤러 실행 전에 호출
- postHandle() - 컨트롤러 실행 후에 호출
- afterCompletion() - 뷰가 렌더링 된 후에 호출
☑️ 등록 방법
WebMvcConfigurer 인터페이스를 구현하여 addInterceptors() 메서드에서 Interceptor를 등록한다.
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// "/api/**" 경로에 대해서만 MyInterceptor를 적용
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/api/**");
}
}
AOP
- 빈(Bean) 메서드 호출 전/후/예외 시에 동작
- 프록시 기반으로 동작
- 트랜잭션 처리, 로깅, 성능 측정, 보안 검사 등을 위해 사용한다.
서로 다른 클래스 사이에 횡단 개념으로 공통 사용되는 부분들이 존재할 경우,
이를 각각 구현하는 것이 아니라 Aspect 단위로 묶어 공통 관리하고 호출할 수 있도록 하는 것
✅ 핵심 용어
용어 | 뜻 |
Aspect | 공통 기능의 모음 |
Advice | 실제 실행될 코드 |
JoinPoint | Advice가 적용될 수 있는 지점 |
Pointcut | Advice를 적용할 조건 |
Target | Advice가 적용되는 실제 객체 |
Weaving | Advice를 Target에 적용하는 과정 |
Advice는 공통 기능을 담고 잇는 실제 실행 코드이다.
"언제 어떤 작업을 수행할 것인가" 에 대한 내용을 담고 있다.
✅ 언제 실행할 것인가?
어노테이션 | 언제 실행되는가? |
@Before | 메서드 실행 전 |
@After | 메서드 실행 후 |
@AfterReturning | 메서드 정상 종료 시 |
@AfterThrowing | 메서드가 예외를 던졌을 때 |
@Around | 메서드 실행 전과 후 모두 |
AOP 구현 예시
@Aspect
@Component
public class LoggingAspect {
// Pointcut 정의: com.example.demo.service 패키지의 모든 메서드에 적용
@Pointcut("execution(* com.example.demo.service..*(..))")
public void allServiceMethods() {}
// Around Advice: 메서드 실행 전/후 시간 측정
@Around("allServiceMethods()")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object result = joinPoint.proceed(); // 실제 서비스 메서드 실행
long end = System.currentTimeMillis();
String methodName = joinPoint.getSignature().toShortString();
System.out.println("⏱️ " + methodName + " 실행 시간: " + (end - start) + "ms");
return result;
}
}
✅ 등록 방법
@Aspect로 선언 후
@Component 또는 @Bean으로 등록한다.
'Web' 카테고리의 다른 글
[Spring] Spring Security (0) | 2025.05.08 |
---|---|
[Spring] QueryDSL 기초 + 페이징 적용 (0) | 2025.05.07 |
로딩 전략과 Fetch Join 그리고 Proxy (0) | 2025.04.17 |
쿠키 Cookie와 세션 Session 그리고 토큰 Token (1) | 2025.04.10 |
DTO (Data Transfer Object) (0) | 2025.03.31 |