[Spring Boot] Listener, Filter, Dispatcher, Interceptor, Aspect, Controller의 라이프사이클

전체적인 흐름 정리

  1. 클라이언트 요청 (GET /api/hello)
  2. Filter에서 요청 처리 (보안, 로깅)
  3. DispatcherServlet이 요청을 HandlerMapping으로 전달
  4. Interceptor에서 preHandle() 실행
  5. Controller가 요청 처리
  6. Service, Repository를 통해 데이터 처리
  7. Controller가 응답 반환
  8. Interceptor에서 postHandle(), afterCompletion() 실행
  9. DispatcherServlet이 응답 반환
  10. Filter에서 응답 처리 후 최종 클라이언트 반환

Listener (리스너)

  • 역할
    • 애플리케이션이나 서블릿 컨텍스트에서 특정 이벤트를 감지하여 동작.
  • 라이프 사이클
    1. Spring Boot 애플리케이션이 시작됨 (SpringApplication.run())
    2. ApplicationListener가 애플리케이션 이벤트 (ContextRefreshedEvent, ApplicationStartedEvent 등)를 감지
    3. 특정 이벤트 발생 시 콜백 메서드 실행
    4. 필요 시 특정 Bean을 초기화하거나 설정 변경 수행
  • 예제 코드
@Component
public class MyApplicationListener implements ApplicationListener<ApplicationReadyEvent> {
    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        System.out.println("애플리케이션이 준비 완료되었습니다.");
    }
}

Filter (필터)

  • 역할
    • HTTP 요청 및 응답을 변형하거나 로깅 등의 전처리를 수행.
  • 라이프 사이클
    1. 사용자가 HTTP 요청 전송
    2. Filter가 요청을 가로채고 처리 (인증, 로깅, CORS 설정 등)
    3. 요청을 DispatcherServlet에 전달
    4. 컨트롤러 실행 후 응답 생성
    5. 응답이 다시 Filter를 거쳐 클라이언트로 반환
  • 예제 코드
@Component
@Order(1)  // 여러 필터가 있을 경우 순서 지정
public class MyFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        System.out.println("요청 필터 실행");
        chain.doFilter(request, response);
        System.out.println("응답 필터 실행");
    }
}

DispatcherServlet (디스패처 서블릿)

  • 역할
    • 클라이언트 요청을 적절한 컨트롤러로 전달하는 중앙 허브 역할.
  • 라이프 사이클
    1. 사용자가 HTTP 요청 전송
    2. Filter를 거친 후 DispatcherServlet이 요청을 받음
    3. 요청 URL을 분석하여 적절한 HandlerMapping을 찾음
    4. 적절한 컨트롤러로 요청을 전달컨트롤러가 Service, Repository를 거쳐 응답을 반환
    5. 응답을 ViewResolver가 처리 후 클라이언트에 반환
  • 예제 흐름
    • 요청 -> Filter -> DispatcherServlet -> Interceptor -> Controller -> Service -> Repository
    • 응답 <- Filter <- DispatcherServlet <- Interceptor <- Controller <- Service <- Repository

Interceptor (인터셉터)

  • 역할
    • 컨트롤러 실행 전/후 특정 로직을 추가.
  • 라이프 사이클
    1. 요청이 DispatcherServlet을 통해 컨트롤러로 가기 전 preHandle() 실행
    2. 컨트롤러가 실행된 후 postHandle() 실행
    3. 응답이 클라이언트로 가기 직전 afterCompletion() 실행
  • 예제 코드
@Component
public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        System.out.println("preHandle - 컨트롤러 실행 전");
        return true; // false 반환 시 컨트롤러 실행 안 함
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
        System.out.println("postHandle - 컨트롤러 실행 후");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        System.out.println("afterCompletion - 응답 처리 완료 후");
    }
}
  • Interceptor 등록
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor());
    }
}

Aspect (AOP)

  • 역할
    • 비즈니스 로직과 분리된 공통 관심사(로깅, 트랜잭션 관리, 성능 모니터링)를 처리.
  • 라이프 사이클
    • 특정 메서드 실행 전 @Before 실행
    • 메서드 실행 후 @AfterReturning 실행
    • 예외 발생 시 @AfterThrowing 실행
    • 메서드 실행 완료 후 @After 실행
  • 예제 코드
@Aspect
@Component
public class LoggingAspect {
    @Before("execution(* com.example.service.*.*(..))")
    public void beforeMethod(JoinPoint joinPoint) {
        System.out.println("메서드 실행 전: " + joinPoint.getSignature().getName());
    }

    @AfterReturning("execution(* com.example.service.*.*(..))")
    public void afterReturningMethod(JoinPoint joinPoint) {
        System.out.println("메서드 실행 후: " + joinPoint.getSignature().getName());
    }
}

Controller (컨트롤러)

  • 역할
    • 클라이언트 요청을 처리하고 적절한 응답을 반환.
  • 라이프 사이클
    • DispatcherServlet이 요청을 받아 컨트롤러로 전달
    • 컨트롤러가 요청을 처리 (@RequestMapping, @GetMapping, @PostMapping 등)
    • 요청을 Service, Repository로 전달하여 데이터를 조회 또는 저장
    • 결과를 Model에 담아 View로 반환하거나 JSON 응답을 생성 (@ResponseBody)
    • 응답을 DispatcherServlet이 최종 처리하여 클라이언트에 반환
@RestController
@RequestMapping("/api")
public class MyController {
    @GetMapping("/hello")
    public String hello() {
        return "Hello, Spring Boot!";
    }
}

위로 스크롤