개발을 하다 보면 공통적으로 처리해야 할 업무들이 많다.
공통 업무에 관련된 코드를 페이지마다 작성한다면 비효율적일 것이다.
이에 Spring은 공통적으로 여러 작업을 처리할 수 있는 다음과 같은 기능들을 지원하고 있다.
1. Filter(필터)
2. Interceptor(인터셉터)
3. AOP(Aspect Oriented Programming, 관점 지향 프로그래밍)
이제 필터(Filter)와 인터셉터(Interceptor)가 무엇인지 그리고 차이점에 대해서도 알아보자.
또한, 간략하게 인터셉터(Interceptor)와 AOP에 대해서도 비교해보자.
Filter
요청과 응답을 거른 후 정제
- Dispatcher Servlet에 요청이 전달되기 전/ 후에 url 패턴에 맞는 모든 요청에 대해 부가 작업을 처리하는 서블릿 필터이다.
- 인증, 로깅, 인코딩 처리 등에 사용된다.
- 스프링이 아닌 서블릿 컨테이너(톰캣 등) 레벨에서 동작한다.(스프링 빈으로 등록 가능)
- 모든 요청을 처리할 수 있으나, 스프링의 특정 요청 매핑과는 독립적.
-> 기본적으로 스프링과 무관하게 전역적으로 처리해야 하는 작업들을 처리
ex)
이미지, 데이터 압축, 문자열 인코딩 같이 웹 어플리케이션에 전반적으로 사용되는 기능
보안검사(XSS방어 등)을 하여 올바른 요청이 아닐 경우 차단(스프링 컨테이너 앞단에서 동작하기 때문에 더 안전)
필터의 메소드 종류
필터를 사용하기 위해서는 javax.servlet의 Filter interface를 implement해야 하며, 다음과 같은 메소드를 가진다.
public interface Filter {
//필터 객체를 초기화하고 서비스에 추가하기 위한 메소드이다.
//웹 컨테이너가 1회 init()을 호출하여 필터 객체를 초기화하면 이후 요청들은 doFilter()를 통해 처리된다.
public default void init(
FilterConfig filterConfig) throws ServletException {}
//url-pattern에 맞는 모든 HTTP 요청이 디스패처 서블릿으로 전달되기 전에 웹 컨테이너에 의해 실행되는 메소드이다.
//doFilter의 파라미터로 FilterChain이 있는데, FilterChain의 doFilter 통해 다음 대상으로 요청을 전달할 수 있게 된다.
//chain.doFilter()로 전, 후에 우리가 필요한 처리 과정을 넣어줌으로써 원하는 처리를 진행할 수 있다.
public void doFilter(
ServletRequest request,
ServletResponse response,
FilterChain chain) throws IOException, ServletException{}
//필터 객체를 제거하고 사용하는 자원을 반환하기 위한 메소드이다.
//웹 컨테이너가 1회 destroy()를 호출하여 필터 객체를 종료하면 이후에는 doFilter에 의해 처리되지 않는다.
public default void destroy() {}
}
Interceptor
- 컨트롤러(Controller)의 '핸들러(Handler)'를 호출하기 전과 후에 요청과 응답을 참조하거나 가공할수 있는 일종의 필터
- 스프링 MVC의 Handler(컨트롤러 메서드)와 연관되어 동작하며, DispatcherServlet 이후에 요청을 처리
- 요청 전후에 추가 작업(인증, 권한 확인, 로깅, 공통 비즈니스 로직)을 삽입할 수 있다.
- 스프링 HandlerMapping 및 HandlerAdapter와 밀접하게 동작.
- preHandle, postHandle, afterCompletion 메서드로 구현.
전역적으로 작동되는 필터보다
좀더 세부적으로 적용해야 하는 인증이나 인가 작업들은 컨트롤러로 넘어가기 전에 검사해야 하므로 인터셉터가 처리하기에 적합하다.
동작 흐름
1) DispatcherServlet은 해당 Request 객체를 받아서 분석한뒤 '핸들러 매핑(HandlerMapping)' 에게
사용자의 요청을 처리할 핸들러를 찾도록 요청
2) 그 결과로 핸들러 실행체인(HandlerExectuonChanin)이 동작하게 되는데,
이 핸들러 실행체는 하나이상의 핸들러 인터셉터를 거쳐서 컨트롤러가 실행될수 있도록 구성되어 있다.
(핸들러 인터셉터를 등록하지 않았다면, 곧바로 컨트롤러가 실행된다.
반대로 하나이상의 인터셉터가 지정되어 있다면 지정된 순서에 따라서 인터셉터를 거쳐서 컨트롤러를 실행한다)
웹 컨테이너에서 동작하는 필터와 다르게 스프링 컨텍스트에서 동작
인터셉터의 메소드 종류
org.springframework.web.servlet의 HandlerInterceptor Interface를 implement해야하며 다음과 같은 메소드를 가진다.
public interface HandlerInterceptor {
//Controller가 호출되기 전에 실행된다.
//true 반환 시 요청 진행, false 반환 시 요청 중단.
default boolean preHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
return true;
}
//Controller가 호출된 후에 실행된다.(View 렌더링 전)
//이 메소드는 컨트롤러가 반환하는 ModelAndView 타입의 정보가 제공되는데,
//최근에는 JSON 형태로 데이터를 제공하는 RestAPI 기반의 컨트롤러(@RestController)를 만들면서 자주 사용되지 않는다.
default void postHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
@Nullable ModelAndView modelAndView) throws Exception {
}
//모든 뷰에서 최종 결과를 생성하는 일을 포함해 모든 작업이 완료된 후에 실행된다.(View 렌더링 후)
//요청 처리 중에 사용한 리소스를 반환할 때 사용할 수 있다.
default void afterCompletion(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
@Nullable Exception ex) throws Exception {
}
preHandle 메소드
컨트롤러 이전 처리
return 값이 true면 다음 단계 진행, false면 작업 중단.
3번째 파라미터로 Object 타입의 handler 파라미터는 핸들러 매핑이 찾아준 컨트롤러 빈에 매핑되는 HandlerMethod라는 새로운 타입의 객체로써, @RequestMapping이 붙은 메소드의 정보를 추상화한 객체이다.
현재 실행되는 컨트롤러를 파악하거니, 추가적인 메소드를 실행하는 등의 작업이 가능하다.
postHandle 메소드
컨트롤러 이후 처리
이 메소드는 컨트롤러가 반환하는 ModelAndView 타입의 정보가 제공되는데, 최근에는 JSON 형태로 데이터를 제공하는 RestAPI 기반의 컨트롤러(@RestController)를 만들면서 자주 사용되지 않는다.
또한 컨트롤러 하위 계층에서 작업을 진행하다가 중간에 예외가 발생하면 postHandle은 호출되지 않는다.
afterCompletion 메소드
모든 뷰에서 최종 결과를 생성하는 일을 포함해 모든 작업이 완료된 후에 실행
요청 처리 중에 사용한 리소스를 반환할 때 사용하기에 적합하다.
postHandler과 달리 컨트롤러 하위 계층에서 작업을 진행하다가 중간에 예외가 발생하더라도 afterCompletion은 반드시 호출된다.
인터셉터 vs AOP
인터셉터 대신에 컨트롤러에 적용할 부가기능을 어드바이스로 만들어 AOP로 적용할 수도 있다.
다만 다음과 같은 이유로 컨트롤러의 호출 과정에 적용되는 부가기능들은 인터셉터를 사용하는 것이 낫다.
1. 컨트롤러는 타입과 실행 메소드가 모두 제각각이라 포인트컷(적용할 메소드 선별)의 작성이 어렵다.
2. 컨트롤러는 파라미터나 리턴 값이 일정하지 않다.
즉, 타입이 일정하지 않고, 호출 패턴도 정해져 있기 때문에 컨트롤러에 AOP를 적용하려면 번거로운 부가 작업들이 생기게 된다.
정리
특성 | Filter | Interceptor |
동작 위치 | DispatcherServlet 이전 | DispatcherServlet 이후 |
사용 영역 | 서블릿 컨테이너 레벨 | Spring MVC레벨 |
목적 | 요청/응답 전처리, 공통적인 작업 | 컨트롤러 전후 처리, 비즈니스 로직 보조 |
스프링과의 통합성 | 스프링 독립적 | 스프링 MVC에 밀접하게 결합 |
URL 매핑 제어 | 직접 코드로 매핑(Spring Boot Filter Chain) | addPathPatterns/excludePathPatterns |
View렌더링 후 처리 가능 | 가능 | 가능(afterCompletion) |
참고
https://mangkyu.tistory.com/173
'Spring' 카테고리의 다른 글
[Spring] Spring에서의 요청처리 흐름(+Spring Security/MVC의 에러 처리 위치) (0) | 2024.11.26 |
---|---|
[Spring Security] 401, 403 에러처리(Spring 3.xx) (13) | 2024.11.26 |
Spring 프로젝트에서 웹소켓 적용하기~!! 2탄 (3) | 2024.06.12 |
Spring 프로젝트에서 웹소켓 적용하기~!! 1탄 (5) | 2024.06.10 |
Google Oauth2 (0) | 2024.04.02 |