Spring/그 외

[Spring] 서블릿 필터 & 핸들러 인터셉터

ummchicken 2023. 2. 8. 14:37

오늘도 역시 기본에 대한 내용이다.

기본 중의 기본인 내용이지만... 이제야 정리한다.


✔️ 필터(Filter) / 인터셉터(Interceptor) / AOP


스프링에서 요청이 Controller로 들어오기 전에 처리해야 하는 작업이 있다.

대표적으로 인증 / 인가, XSS 방어, 데이터 압축, 인코딩 등이 있다.

💡 이러한 작업들을 공통 관심사로 보고, 분리하는 것이 효율적이다.
→ 이때 사용할 수 있는 것이 필터(Filter)와 인터셉터(Interceptor), Spring AOP이다.



이번 포스팅은 닮은 듯 다른 Filter와 Interceptor에 대한 내용이다.


💡 Filter와 Interceptor, AOP는 공통적으로,
여러 작업을 처리함으로써 중복된 코드를 제거할 수 있다는 공통점이 있다.


위 3가지 기능들은 모두
어떤 행동을 하기 전에 먼저 실행하거나, 실행한 후에 추가적인 행동을 할 때 사용되는 기능들이다.


✔️ Filter와 Interceptor, AOP의 흐름

※ 웹 애플리케이션 서버의 요청 응답 구조 (그림)

  • Filter와 Interceptor는 Servlet 단위에서 실행된다.
  • 반면 AOP는 메소드 앞에서 Proxy 패턴으로 실행된다.
  • Filter를 웹 컨테이너(서블릿 컨테이너) 내에 생성한 후 초기화 시 init()이 호출된다.
  • 그리고 doFilter가 호출된다.
  • 컨트롤러에 들어가기 전, preHanlder()가 실행된다.
  • 컨드롤러에 나와 postHandler(), afterCompletion(), doFilter() 순으로 실행된다.
  • 컨트롤러의 메소드 처리가 끝나 return 되고, 화면에 띄워주는 처리가 되기 직전에 prHandler()가 호출된다.
  • 서블릿 종료 시 Filter.destroy()가 실행된다.
  • 즉, 실행순서 : Filter → Interceptor → AOP → Interceptor → Filter


인터셉터와 필터 동작 과정

(내가 그린 그림인데 왤케 웃기지ㅋ)



이제 Filter와 Interceptor, AOP를 하나씩 알아보자.


✔️ 필터 (Filter)란?

필터는 말 그대로 요청과 응답을 거른 뒤, 정제하는 역할을 한다.
💡 DispatcherServlet에 요청이 전달되기 전/후에 url 패턴에 맞는
모든 요청에 대해 부가 작업을 처리할 수 있는 기능을 제공한다.

즉, 스프링 컨테이너가 아닌, 웹 컨테이너(ex. 톰캣)에 의해 관리가 되는 것이고,
Spring 범위 밖에서 처리되는 것이다. (디스패처서블릿 전/후에 처리)
(스프링 빈으로 등록은 됨)

※ DispatcherServlet이란?

더보기

- HTTP 프로토콜로 들어오는 모든 요청을 가장 먼저 받아,

적합한 컨트롤러에 위임해주는 프론트 컨트롤러(Front Controller)이다.

- 클라이언트로부터 어떠한 요청이 오면, Tomcat과 같은 서블릿 컨테이너가 요청을 받는다.

그리고 이 모든 요청을 프론트 컨트롤러인 디스패처서블릿이 가장 먼저 받게 된다.

그러면 디스패처서블릿은 공통적인 작업을 먼저 처리한 후에, 해당 요청을 처리해야 하는 컨트롤러를 찾아서 작업을 위임한다.

- Front Controller는 주로 서블릿 컨테이너의 제일 앞에서 서버로 들어오는 클라이언트의 모든 요청을 받아서 처리해주는 Controller로써, MVC 구조에서 함께 사용되는 디자인 패턴이다.




이러한 과정을 그림으로 보자.

  • 필터(Filter)란, J2EE 표준 스펙이다.
  • J2EE 스펙에 따라 제품으로 구현한 것을 웹 애플리케이션 서버 또는 WAS(ex. 톰캣)라 불린다.
  • 서블릿 필터는 DispatcherServlet 이전에 실행이 되는데, 필터가 동작하도록 지정된 자원의 앞단에서 요청 내용을 변경하거나, 여러가지 체크를 수행할 수 있다.
  • 또한 자원의 처리가 끝난 후, 응답 내용에 대해서도 변경하는 처리를 할 수 있다.
  • 보통 web.xml에 등록하고, 일반적으로 인코딩 변환 처리, XSS 방어 등의 요청에 대한 처리로 사용된다.


※ 웹서버(Web Server)와 웹 애플리케이션 서버(WAS)의 차이

더보기

- 웹 서버 (Web Server) : HTTP 요청을 받아 Static contents를 제공하는 서버, 프로그램.

HTTP 프로토콜을 기반으로 하여 클라이언트의 요청을 서비스하는 기능을 담당. (ex. Apach Server, Nignx, ...)

기능 1 - 정적인 컨텐츠 제공 : WAS를 거치지 않고, 바로 요청한 컨텐츠를 제공할 수 있다.

기능 2 - 동적인 컨텐츠 제공을 위한 요청 전달 : 요청을 WAS에 보내고, WAS가 처리한 결과를 클라이언트에게 전달한다.

- 웹 애플리케이션 서버 (WAS, Web Application Server) : 다양한 서버 내 알고리즘, 비즈니스 로직, DB 조회 등 클라이언트 요청에 따라 동적인 컨텐츠를 제공하는 서버, 프로그램.

HTTP 프로토콜을 기반으로 하여 클라이언트의 요청에 따라 구현된 비즈니스 로직을 통해 동적으로 만들어진 컨텐츠를 반환. (ex. Tomcat, ...)

또한 데이터베이스 접속 가능, 여러 개의 트랜잭션 관리 등 수행.

- WAS = Web Server + Web Container

- 컨테이너(Container)는 무엇인가?

웹 서버가 보낸 JSP, PHP, ASP.net 등의 파일들을 실행하고, 수행결과를 다시 웹 서버로 보내주는 역할을 한다.

- 결국, 웹 어플리케이션 서버는

1. 웹 서버에서 요청을 받고,

2. 이를 웹 컨테이너(서블릿 컨테이너)로 보내 로직(알고리즘, DB 연결 등)을 수행하고,

3. 그 결과를 다시 웹 서버로 보내,

4. 최종적으로 클라이언트에게 보내주는 것이다.



✔️ 필터(Filter)의 메소드 종류

필터를 사용하기 위해서는 javax.servlet의 Filter 인터페이스를 구현(implements)해야 하며, 다음과 같은 메소드를 가진다.
public interface Filter {
 
    public default void init(FilterConfig filterConfig) throws ServletException {}
 
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException;
 
    public default void destroy() {}
  • init() : 필터 객체를 초기화하고, 서비스에 추가하기 위한 메소드이다.
    • 웹 컨테이너(서블릿 컨테이너)가 1회 init()을 호출하여 필터 객체를 초기화하면, 이후 요청들은 doFilter()를 통해 처리된다.

  • doFilter() : 모든 HTTP 요청이 디스패처서블릿으로 전달되기 전에, 웹 컨테이너에 의해 실행되는 메소드이다.
    • doFilter의 파라미터로 FilterChain이 있는데, FilterChain의 doFilter를 통해 다음 대상으로 요청을 전달할 수 있다.
    • chain.doFilter()로 전/후에 우리가 필요한 처리 과정을 넣어줌으로써, 원하는 처리를 진행할 수 있다.

  • destory() : 필터 객체를 제거하고, 사용하는 자원을 반환하기 위한 메소드이다.
    • 웹 컨테이너가 1회 destroy()를 호출하여 필터 객체를 종료하면, 이후에는 doFilter에 의해 처리되지 않는다.




✔️ 인터셉터 (Interceptor)란?

쉽게 말해, 요청에 대한 작업 전/후로 가로챈다고 보면 된다.
💡 DispatcherServlet이 Controller를 호출하기 전/후에 인터셉터가 끼어들어 요청과 응답을 참조하거나, 가공할 수 있는 기능을 제공한다.

웹 컨테이너에서 동작하는 필터와 달리,
인터셉터는 스프링 컨텍스트에서 동작한다.

  • 인터셉터를 사용하면, 브라우저 요청이 있을 때 요청 메서드 호출 전후에 개발자가 원하는 기능을 수행할 수 있다.
  • 브라우저의 요청을 해당 컨트롤러의 메서드가 처리하기 전후에 인터셉터를 두어 특정 작업을 수행한다.
  • 인터셉터는 필터와 기슷한 기능을 하지만, 필터는 웹 애플리케이션의 특정한 위치에서만 동작하는 데 반해, 인터셉터는 좀 더 자유롭게 위치를 변경해서 기능을 수행할 수 있다.
  • 즉, 인터셉터는 애플리케이션 안에서 적용 범위를 설정할 수 있다.
  • 주로 쿠키 제어, 파일 업로드 작업 등에 사용한다.



✔️ 인터셉터(Interceptor)의 메소드 종류

인터셉터를 추가하기 위해서 org.springframework.web.servlet의 HandlerInterceptor 인터페이스를 구현(implements) 해야 하며, 다음과 같은 메소드를 가진다.
public interface HandlerInterceptor {
 
	default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
 
		return true;
	}
 
	default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			@Nullable ModelAndView modelAndView) throws Exception {
	}
 
	default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
			@Nullable Exception ex) throws Exception {
	}
  • preHandler() : Controller 실행 전 호출된다.
    • 컨트롤러 이전에 처리해야 하는 전처리 작업이나 요청 정보를 가공하거나 추가하는 경우에 사용.
  • postHandler() : Controller 실행 후 DispatcherServlet이 View로 보내기 전에 호출된다.
    • 컨트롤러 이후에 처리해야 하는 후처리 작업이 있을 때 사용할 수 있다.
  • afterCompletion() : View 생성을 포함한 모든 작업이 완료된 후에 실행된다.
    • 요청 처리 중에 사용한 리소스를 반환할 때사용할 수 있다.



✔️ AOP

Spring AOP는 Spring에서 지원하는 관점 지향 프로그래밍을구현할 수 있는 기술이다.

AOP의 Advice는 '로깅', '트랜잭션', '에러 처리' 등 비즈니스단의 메소드에서 조금 더 세밀하게 조정하고 싶을 때 사용한다.
인터셉터와 달리 주소(URL), 파라미터, 애노테이션 등 PointCut이 지원하는 다양한 방법으로 대상을 지정할 수 있다.

즉, 필터와 인터셉터는 요청과 응답 시 DispatcherServlet이나 Handler 주변에서 동작한다.
반면, AOP는 비즈니스단에서도 동작이 가능하다는 장점이 있다.



✔️ Filter와 Interceptor의 사용 기준


그러면 언제 필터를 사용하고, 언제 인터셉터를 사용할까?

가장 큰 차이는 아래 두 가지이다.

  1. 실행 시점이 다르다.
  2. 필터는 Web Application에 등록하고, 인터셉터는 Spring Context에 등록한다.

  필터 인터셉터
관리되는 컨테이너 웹 컨테이너 스프링 컨테이너
Request/Response 객체 조작 가능 여부 O X
용도 - 공통된 보안 및 인증/인가 관련 작업
- 모든 요청에 대한 로깅 또는 감사
- 이미지/데이터 압축 및 문자열 인코딩
- Spring과 분리되어야 하는 기능
- 세부적인 보안 및 인증/인가 공통 작업
- API 호출에 대한 로깅 또는 감사
- Controller로 넘겨주는 정보(데이터)의 가공

※ Request, Response 객체 조작 가능 여부

더보기

💡 필터는 Request와 Response를 조작할 수 있지만, 인터셉터는 조작할 수 없다.

  • 필터
public class MyFilter implements Filter {
 
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
    throws IOException, ServletException {
        // 다른 request와 response를 넣어줄 수 있음
        chain.doFilter(request, response);
    }
}

→ 필터가 다음 필터를 호출하기 위해서는 필터 체이닝(다음 필터 호출)을 해야 한다.

→ 이때 request, response 객체를 넘겨주므로, 우리가 원하는 request, response 객체를 넣어줄 수 있다.

하지만 인터셉터는 처리 과정이 필터와 다르다.

  • 인터셉터
public class MyInterceptor implements HandlerInterceptor {
 
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) 
    throws Exception {
        // Request, Response를 교체할 수 없고 boolean 값만 반환 가능
        return true;
    }
}

→ 디스패처서블릿이 여러 인터셉터 목록을 가지고 있고, 순차적으로 실행시킨다.

→ 그리고 true를 반환하면 다음 인터셉터가 실행되거나 컨트롤러로 요청이 전달되며, false가 반환되면 요청이 중단된다.

→ 그러므로 다른 request, response 객체를 넘겨줄 수 없다.



✔️ Filter와 Interceptor의 차이점

1. 적용 시점이 다름

  • Filter → Interceptor → AOP


2. 적용 방식이 다름

  • Filter : web.xml
  • Interceptor : servlet-context.xml


3. 실행 위치가 다름

  • Interceptor, Filter : Servlet 단위에서 실행
  • AOP : 메소드 앞에 Proxy 패턴의 형태로 실행




✔️ 필터와 인터셉터의 용도 및 예시

💡 필터의 용도 및 예시

  • 공통된 보안 및 인증/인가 관련 작업
  • 모든 요청에 대한 로깅 또는 감사
  • 이미지/데이터 압축 및 문자열 인코딩
  • Spring과 분리되어야 하는 기능
💡 필터는 기본적으로 스프링과 무관하게 전역적으로 처리해야 하는 작업들을 처리할 수 있다.

웹 애플리케이션에 전반적으로 사용되는 기능을 구현하기에 적당하다.
Ex) 이미지나 데이터 압축, 문자열 인코딩
💡 Filter는 다음 체인으로 넘기는 ServletRequest와 ServletResponse를 조작할 수 있다는 점에서 Interceptor보다 훨씬 강렬한 기술이다.
💡 SpringSecurity의 특징 중 하나가 Spring MVC에 종속적이지 않다는 것인데,
바로 Filter를 기반으로 인증/인가 처리를 하기 때문이다.

※ 전체적인 Spring MVC 처리 프로세스



💡 인터셉터의 용도 및 예시

  • 세부적인 보안 및 인증/인가 공통 작업
  • API 호출에 대한 로깅 또는 감사
  • Controller로 넘겨주는 정보의 가공
💡 인터셉터에서는 클라이언트의 요청과 관련되어 전역적으로 처리해야 하는 작업들을 처리할 수 있다.

Ex) 특정 그룹의 사용자가 어떤 기능을 시용하지 못하게 해야 할 경우,
Controller로 넘어가기 전에 검사해야 하므로 인터셉터가 처리하기 적합하다.
💡 인터셉터는 필터와 다르게 HttpServletRequest나 HttpServletResponse 등과 같은 객체를 제공받으므로 객체 자체를 조작할 수는 없다.

하지만 내부적으로 갖는 값은 조작할 수 있으므로,
컨트롤러로 넘겨주기 위한 정보를 가공하기에는 용이하다.




✔️ 정리 겸 요약

💡 필터 & 인터셉터

  • 필터(Fiter)는 특정 요청과 컨트롤러에 관계 없이 전역적으로 처리해야하는 작업이나, 웹 어플리케이션에 전반적으로 사용되는 기능을 구현할 때 적용한다.
  • 인터셉터(Interceptor)는 클라이언트의 요청과 관련된 작업에 대해, 추가적인 요구사항을 만족해야 할 때 적용한다.


💡 웹 서버 & 웹 애플리케이션 서버

  • 웹 서버(WS)에서는 웹 브라우저같은 클리이언트로부터 HTTP 요청을 받아들이고, HTML 문서와 같은 웹 페이지를 정적으로 처리해 반환한다. 단순히 저장되어 있는 웹 페이지를 클라이언트로 전달하고, 클라이언트로부터 컨텐츠를 전달받아 저장하거나 처리하는 역할을 담당한다.
  • 웹 애플리케이션 서버(WAS)는 WS와 가장 큰 차이점으로 동적 서버 콘텐츠를 수행한다. 웹 서버 + 웹 컨테이너이다. 즉, 프로그램 실행 환경과 DB 접속 기능을 제공하고, 여러 개의 트랜잭션을 관리하며, 요청된 비즈니스 로직을 수행한다.
  • 웹 컨테이너(Web Container)JSP와 Servlet을 실행시킬 수 있는 소프트웨어로, 웹 서버에서 JSP를 요청하면 톰캣에서 JSP파일을 서블릿으로 변환 후 컴파일을 수행하는 역할을 한다.


💡 진짜 마지막 필터 & 인터셉터 정리...

  • 필터는 자바가 지원하는 기능이고, 인터셉터는 스프링이 지원하는 기능이다.
  • 필터는 웹 애플리케이션에서 동작하고, 인터셉트는 스프링 컨텍스트에서 동작한다.
  • 필터는 DistpatcherServlet보다도 앞에서 동작할 수 있다.
    • ServletRequest, ServletResponse를 받아서 처리하는 것이 가능하다.
  • 인터셉터는 필터와 달리, 컨트롤러가 동작한 후에 작업을 처리할 수 있다.
    • Ex) ViewController에서 뷰를 생성한 것에 따라 동적으로 처리하는 일이 가능하다.






출처