스프링 코드를 프로그램을 구현할 때 공통적으로 처리해야할 업무들이 많다. 공통업무에 관련된 코드를 모든 페이지 마다 작성해야한다면 중복된 코드가 많아지게 되면 소스관리가 힘들어진다.
스프링에서 공통처리를 위해 다음을 활용할 수 있다.
서블릿 필터는 서블릿 실행 전, 후에 어떤 작업을 하고자 할때 사용한다. 그래서 DispatcherServlet 앞단에서 실행이 되며 즉, 스프링 컨테이너 밖에 위치한다. 클라이언트와 자원 사이에 여러 필터가 모여서 하나의 체인으로 구성되어 있다. 대표적으로 인코딩 변환처리, XSS 방어, LOG, 보안, 이미지변환, 데이터압축, 캐시 등을 구현할때 사용한다.
필터를 추가하기 위해서는 javax.servlet의 Filter 인터페이스를 구현(implements)해야 하며, 3가지 메소드를 가지고 있다.
public default void init(FilterConfig filterConfig) throws ServletException {}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException;
① 서블릿 컨테이너는 웹 어플리케이션을 시작할 때 DD파일(web.xml)에 등록된 필터의 인스턴스를 생성하고 init()을 호출한다.
② 클라이언트 요청이 들어오면 해당하는 필터의 doFilter()를 호출한다.
③ doFilter()에서 작업을 실행하고 다음 필터의 doFilter()를 호출한다.
④ 마지막 필터까지 ③을 반복한다.
⑤ 마지막 필터는 서블릿의 service()를 호출한다.
⑥ 서블릿의 service()가 끝나면 service()를 호출했던 이전 필터로 돌아간다.
⑦ 반복해서 제일 처음 호출됐던 필터까지 돌아간다.
⑧ 마지막으로 클라이언트에게 응답 결과를 보낸다.
인터셉터는 Spring이 제공하는 기술로써, 디스패처 서블릿이 Controller(Handler)를 호출하기 전, 후에 요청과 응답에 특정 작업을 처리할 수 있다.
대표적으로 인증/인가 등과 같은 공통작업, controller로 넘겨주는 정보의 가공, 로그인 처리 시 많이 사용된다.
인터셉터를 추가하기 위해서는 org.springframework.web.servlet의 HandlerInterceptor 인터페이스를 구현해야 하며, 다음의 3가지 메소드를 가지고 있다.
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
{ return true; }
postHandle 메소드는 컨트롤러를 호출된 후에 처리해야 하는 후처리 작업이 있을 때 사용할 수 있다. 이 메소드에는 컨트롤러가 반환하는 ModelAndView 타입의 파라미터가 제공되는데, 최근에는 Json 형태로 데이터를 제공하는 RestAPI 기반의 컨트롤러(@RestController)를 만들면서 자주 사용되지는 않는다.
afterCompletion 메소드는 이름 그대로 모든 뷰에서 최종 결과를 생성하는 일을 포함해 모든 작업이 완료된 후에 실행된다. 요청 처리 중에 사용한 리소스를 반환할 때 사용하기에 적합하다.
DispatcherServlet이 클라이언트 요청을 받는다.
HandlerMapping으로 부터 주어진 request를 처리할 수 있는 Handler객체를 가져온다.
가져온 Handler를 실행(invoke) 시킬 수 있는 HandlerAdapter객체를 할당
해당 Controller를 처리할 Handler객체에 적용할 interceptor가 존재한다면, prehandle 메소드를 호출
컨트롤러의 메소드를 실행 후 ModelAndView를 얻는다.
postHandle
ModelAndView를 통해 view name을 ViewResolver에게 전달하여 응답에 필요한 View객체를 얻어온다.
View객체에 Model을 파라미터로 넘겨주어 render메소드를 호출
afterCompletion
preHandle이 예외를 발생시키면 뒤에 있던 postHandle이 호출되지 않는다. 하지만 afterCompletion은 항상 호출이 된다.
실행 시점
작업 범위
사용 영역 : 주로 인코딩이나 보안 관련 처리와 같은 web app의 전역적으로 처리해야 하는 로직은 필터로 구현하고 클클라이언트의 요청과 관련되어 전역적으로 처리해야 하는 작업에 대해서는 주로 인터셉터에서 처리한다.
대표적으로 필터(Filter)를 인증과 인가에 사용하는 도구로는 SpringSecurity가 있다. SpringSecurity의 특징 중 하나는 Spring MVC에 종속적이지 않다는 것인데, 이러한 이유로는 필터 기반으로 인증/인가 처리를 하기 때문이다.
인터셉터 대신에 컨트롤러들에 적용할 부가기능을 advice로 만들어 AOP를 적용할 수 있다.
하지만,
따라서, 컨트롤러에 AOP를 적용하려면 복잡할 수 있어 부가기능들은 인터셉터를 사용하는 편이 낫다.