HTTP 요청이 들어와서 @RestController의 메서드가 실행되기까지 수많은 컴포넌트를 거칩니다.
Filter, DispatcherServlet, Interceptor, AOP가 각각 어느 시점에 무슨 역할을 하는지 알아야
인증·로깅·트랜잭션 처리를 올바른 위치에 구현할 수 있습니다.
DispatcherServlet은 Front Controller 패턴의 구현체입니다.
모든 HTTP 요청을 하나의 서블릿이 받아서 적절한 핸들러(Controller)에게 위임합니다.
// 1. HandlerMapping으로 Handler 탐색
// @RequestMapping URL 패턴 → Controller 메서드
HandlerExecutionChain handler =
handlerMapping.getHandler(request);
// 2. HandlerAdapter 선택
// 메서드 시그니처에 맞는 어댑터 선택
// 파라미터 바인딩, 리턴값 처리 담당
HandlerAdapter adapter =
getHandlerAdapter(handler.getHandler());
// 3. 핸들러 실행
ModelAndView mv =
adapter.handle(request, response, handler);
// 4. ViewResolver (REST API는 건너뜀)
// @ResponseBody → MessageConverter로 직렬화
// → JSON/XML 응답 바디 작성
// @Controller: View 이름 반환
@Controller
public class PageController {
@GetMapping("/home")
public String home(Model model) {
model.addAttribute("msg", "hello");
return "home"; // ViewResolver → home.html
}
}
// @RestController: 객체를 Body로 직렬화
// @Controller + @ResponseBody 합성
@RestController
public class ApiController {
@GetMapping("/api/user")
public UserDto getUser() {
return new UserDto("kim"); // → JSON
// MessageConverter(Jackson)이 직렬화
}
}
| 구분 | 실행 위치 | 접근 가능한 것 | 주요 용도 |
|---|---|---|---|
| Filter | 서블릿 컨테이너 (Tomcat) Spring 컨텍스트 밖 |
HttpServletRequest/Response ServletContext (Spring Bean 주입 가능하지만 주의) |
인코딩 설정 CORS 헤더 처리 보안 (Spring Security는 Filter 기반) 요청/응답 로깅 응답 압축 |
| Interceptor | DispatcherServlet 이후 Spring 컨텍스트 내 |
HttpServletRequest/Response Handler(Controller 메서드 정보) Spring Bean 자유롭게 사용 |
인증/인가 체크 로그인 여부 확인 요청 처리 시간 측정 공통 모델 데이터 주입 |
| AOP | Spring Bean 메서드 실행 시점 (프록시 레이어) |
메서드 파라미터, 리턴값, 예외 JoinPoint 정보 HTTP 정보 없음 |
트랜잭션 (@Transactional) 성능 측정 (메서드 단위) 캐싱 (@Cacheable) 감사 로그 (비즈니스 메서드) |
@Component
public class CorsFilter implements Filter {
@Override
public void doFilter(
ServletRequest req,
ServletResponse res,
FilterChain chain)
throws IOException, ServletException {
HttpServletResponse response =
(HttpServletResponse) res;
response.setHeader(
"Access-Control-Allow-Origin", "*");
response.setHeader(
"Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE");
chain.doFilter(req, res); // 다음 필터로
}
}
@Component
public class AuthInterceptor
implements HandlerInterceptor {
@Override
public boolean preHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler) {
String token = request.getHeader("Authorization");
if (!tokenService.validate(token)) {
response.setStatus(401);
return false; // Controller 실행 중단
}
return true; // 계속 진행
}
@Override
public void afterCompletion(..., Exception ex) {
// 요청 처리 완료 후 항상 실행
// 예외 발생해도 실행됨 (리소스 정리)
}
}
실행 위치가 다릅니다. Filter는 서블릿 컨테이너(Tomcat) 레벨에서 동작합니다 — Spring ApplicationContext 바깥입니다. 모든 서블릿 요청을 가로챌 수 있고, Spring Security가 이 레이어를 사용합니다. Interceptor는 DispatcherServlet 이후 Spring 컨텍스트 내부에서 동작합니다. Handler(어떤 Controller 메서드가 처리할지) 정보를 알 수 있고, Spring Bean을 자유롭게 주입해 쓸 수 있습니다. 정적 리소스(css, js)는 DispatcherServlet에서 처리되지 않는 경우 Interceptor를 통과하지 않을 수 있지만, Filter는 항상 통과합니다.
Interceptor는 HTTP 요청 단위로만 동작합니다.
AOP는 HTTP와 관계없이 임의의 Spring Bean 메서드에 적용할 수 있습니다.
예를 들어 배치 서비스, 스케줄러, 이벤트 리스너 메서드에 트랜잭션이나 성능 측정을 적용할 때는
Interceptor로 할 수 없고 AOP를 써야 합니다.
또한 메서드 파라미터나 리턴값에 접근해야 할 때도 AOP의 @Around가 유리합니다.
Front Controller가 없으면 각 서블릿이 공통 처리(인증, 로깅, 예외 처리)를 중복으로 구현해야 합니다. DispatcherServlet이 모든 요청의 단일 진입점 역할을 하면서 공통 처리는 한 곳에서, 실제 비즈니스는 각 Controller에서 담당하는 구조가 됩니다. 확장도 용이합니다 — 새 Controller를 추가할 때 Servlet 등록 없이 @RequestMapping만 선언하면 됩니다.
Filter(서블릿 컨테이너) → DispatcherServlet → Interceptor → AOP → Controller 순서로 요청이 흐르며, 인증/CORS는 Filter, 로그인 체크는 Interceptor, 트랜잭션/캐싱은 AOP가 담당한다.