-
Spring 필터(Filter), 인터셉터(Interceptor), AOPSpring 2023. 3. 16. 15:34
스프링은 공통적으로 여러 작업을 처리함으로써 중복된 코드를 제거할 수 있도록 많은 기능들을 지원하고 있다. 스프링에서 공통된 처리를 위해 필터, 인터셉터, AOP를 사용할 수 있다.
필터(Filter)
필터는 J2EE 표준 스펙 기능으로 디스패처 서블릿에 요청이 전달되기 전/후에 url 패턴에 맞게 모든 요청에 대해 부가작업을 처리할 수 있는 기능을 제공한다.
디스패처 서블릿은 스프링의 가장 앞단에 존재하는 프론트 컨트롤러이므로, 필터는 스프링 범위 밖에서 처리 되는 것이다.
즉, 스프링 컨테이너가 아닌 톰캣과 같은 웹 컨테이너에 의해 관리가 되고, 디스패처 서블릿 전/후에 처리하는 것이다.
디스패처 서블릿(Displatcher Servlet)
HTTP 프로토콜로 들어오는 모든 요청을 가장 먼저 받아 적합한 컨트롤러에 위임해주는 프론트 컨트롤러(Front Controller)
클라이언트로부터 어떠한 요청이 오면 Tomcat(톰캣)과 같은 서블릿 컨테이너가 요청을 받게 된다. 그리고 이 모든 요청을 프론트 컨트롤러인 디스패처 서블릿이 가장 먼저 받게 된다. 그러면 디스패처 서블릿은 공통적인 작업을 먼저 처리한 후에 해당 요청을 처리해야 하는 컨트롤러를 찾아서 작업을 위임한다.
- 클라이언트의 요청을 디스패처 서블릿이 받는다.
- 요청 정보를 통해 요청을 위임할 컨트롤러를 찾는다.
- 요청을 컨트롤러로 위임할 핸들러 어댑터를 찾아서 전달한다.
- 핸들러 어댑터가 컨트롤러로 요청을 위임한다.
- 비지니스 로직을 처리한다.
- 컨트롤러가 반환값을 반환한다.
- 핸들러 어댑터가 반환값을 처리한다.
- 서버의 응답을 클라이언트로 반환한다.
필터의 메소드
필터를 추가하기 위해서는 javax.servlet의 Filter 인터페이스를 구현(implements)해야 하며 이는 다음의 3가지 메소드를 가지고 있다.
- init 메소드
- doFilter 메소드
- destroy 메소드
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 메소드
init 메소드는 필터 객체를 초기화하고 서비스에 추가하기 위한 메소드이다. 웹 컨테이너가 1회 init 메소드를 호출하여 필터 객체를 초기화하면 이후의 요청들은 doFilter를 통해 처리된다.
doFilter 메소드
doFilter 메소드는 url-pattern에 맞는 모든 HTTP 요청이 디스패처 서블릿으로 전달되기 전에 웹 컨테이너에 의해 실행되는 메소드이다. doFilter의 파라미터로는 FilterChain이 있는데, FilterChain의 doFilter 통해 다음 대상으로 요청을 전달하게 된다. chain.doFilter() 전/후에 우리가 필요한 처리 과정을 넣어줌으로써 원하는 처리를 진행할 수 있다.
destroy 메소드
destroy 메소드는 필터 객체를 서비스에서 제거하고 사용하는 자원을 반환하기 위한 메소드이다. 이는 웹 컨테이너에 의해 1번 호출되며 이후에는 이제 doFilter에 의해 처리되지 않는다.
인터셉터(Interceptor)
인터셉터(Interceptor)는 필터와 달리 Spring이 제공하는 기술로써, 디스패처 서블릿(Dispatcher Servlet)이 컨트롤러를 호출하기 전과 후에 요청과 응답을 참조하거나 가공할 수 있는 기능을 제공한다.
즉, 웹 컨테이너에서 동작하는 필터와 달리 인터셉터는 스프링 컨텍스트에서 동작을 하는 것이다.
디스패처 서블릿은 핸들러 매핑을 통해 적절한 컨트롤러를 찾도록 요청하는데, 그 결과로 실행 체인(HandlerExecutionChain)을 돌려준다. 그래서 이 실행 체인은 1개 이상의 인터셉터가 등록되어 있다면 순차적으로 인터셉터들을 거쳐 컨트롤러가 실행되도록 하고, 인터셉터가 없다면 바로 컨트롤러를 실행한다.
인터셉터는 스프링 컨테이너 내에서 동작하므로 필터를 거쳐 프론트 컨트롤러인 디스패처 서블릿이 요청을 받은 이후에 동작하게 되는데, 이러한 호출 순서를 그림으로 표현하면 다음과 같다.
인터셉터의 메소드
인터셉터를 추가하기 위해서는 org.springframework.web.servlet의 HandlerInterceptor 인터페이스를 구현(implements)해야 하며, 이는 다음의 3가지 메소드를 가지고 있다.
- preHandle 메소드
- postHandle 메소드
- afterCompletion 메소드
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 { } }
preHandle 메소드
preHandle 메소드는 컨트롤러가 호출되기 전에 실행된다. 그렇기 때문에 컨트롤러 이전에 처리해야 하는 전처리 작업이나 요청 정보를 가공하거나 추가하는 경우에 사용할 수 있다.
preHandle의 반환 타입은 boolean인데 반환값이 true이면 다음 단계로 진행이 되지만, false라면 작업을 중단하여 이후의 작업(다음 인터셉터 또는 컨트롤러)은 진행되지 않는다.
postHandle 메소드
postHandle 메소드는 컨트롤러를 호출된 후에 실행된다. 그렇기 때문에 컨트롤러 이후에 처리해야 하는 후처리 작업이 있을 때 사용할 수 있다. 이 메소드에는 컨트롤러가 반환하는 ModelAndView 타입의 정보가 제공되는데, 최근에는 Json 형태로 데이터를 제공하는 RestAPI 기반의 컨트롤러(@RestController)를 만들면서 자주 사용되지는 않는다.
또한 컨트롤러 하위 계층에서 작업을 진행하다가 중간에 예외가 발생하면 postHandle은 호출되지 않는다.
afterCompletion 메소드
afterCompletion 메소드는 이름 그대로 모든 뷰에서 최종 결과를 생성하는 일을 포함해 모든 작업이 완료된 후에 실행된다. 요청 처리 중에 사용한 리소스를 반환할 때 사용하기에 적합하다. postHandler과 달리 컨트롤러 하위 계층에서 작업을 진행하다가 중간에 예외가 발생하더라도 afterCompletion은 반드시 호출된다.
AOP
- AOP는 OOP를 보완하기 위해 나온 개념으로, 관점 지향 프로그래밍이라고 불린다.
- 비즈니스 로직의 어떠한 동작 전후로 중복되는 부분을 줄이기 위해 사용된다.
- 주로 로깅, 트랜잭션, 에러 처리 등 비즈니스단의 메소드에서 조금 더 세밀하게 조정할 때 사용한다.
- Interceptor나 Filter와는 달리 메소드 전후의 지점에 자유롭게 설정이 가능하고 주소, 파라미터, 어노테이션 등 다양한 방법으로 대상을 지정할 수 있다.
- AOP의 @Advice는 Filter, HandlerInterceptor와 다르게 HttpServletRequest/Response 가 아닌 JoinPoint나 ProceedingJoinPoint 등을 활용해서 호출한다.
AOP의 메소드
@Before 대상 메소드의 수행 전 @After 대상 메소드의 수행 후 @After-returning 대상 메소드의 정상적인 수행 후 @After-throwing 예외 발생 후 @Around 대상 메소드의 수행 전, 후 인터셉터, AOP 차이
인터셉터와 AOP 둘 다 스프링에서 자체적으로 기술을 제공하며, 공통 관심사 코드를 뽑아내 적용시키기 위해 나왔다.
- AOP 는 메서드 동작의 전 후 과정에 부가로직을 입힐 수 있다.
- Interceptor 는 핸들러 동작의 전 후 과정에 부가로직을 입힐 수 있다.
필터와 인터셉터의 차이
필터(Filter)의 용도
- 공통된 보안 및 인증/인가 관련 작업
- 모든 요청에 대한 로깅 또는 감사
- 이미지/데이터 압축 및 문자열 인코딩
- Spring과 분리되어야 하는 기능
필터에서는 기본적으로 스프링과 무관하게 전역적으로 처리해야 하는 작업들을 처리할 수 있다.
대표적으로 보안 공통 작업이 있다. 필터는 인터셉터보다 앞단에서 동작하므로 전역적으로 해야하는 보안 검사(XSS 방어 등)를 하여 올바른 요청이 아닐 경우 차단을 할 수 있다. 그러면 스프링 컨테이너까지 요청이 전달되지 못하고 차단되므로 안정성을 더욱 높일 수 있다.
또한 필터는 이미지나 데이터의 압축이나 문자열 인코딩과 같이 웹 애플리케이션에 전반적으로 사용되는 기능을 구현하기에 적당하다. Filter는 다음 체인으로 넘기는 ServletRequest/ServletResponse 객체를 조작할 수 있다는 점에서 Interceptor보다 훨씬 강력한 기술이다.
대표적으로 필터(Filter)를 인증과 인가에 사용하는 도구로는 SpringSecurity가 있다. SpringSecurity의 특징 중 하나는 Spring MVC에 종속적이지 않다는 것인데, 이러한 이유로는 필터 기반으로 인증/인가 처리를 하기 때문이다.
인터셉터(Interceptor)의 용도
- 세부적인 보안 및 인증/인가 공통 작업
- API 호출에 대한 로깅 또는 감사
- Controller로 넘겨주는 정보(데이터)의 가공
인터셉터에서는 클라이언트의 요청과 관련되어 전역적으로 처리해야 하는 작업들을 처리할 수 있다.
대표적으로 세부적으로 적용해야 하는 인증이나 인가와 같이 클라이언트 요청과 관련된 작업 등이 있다. 예를 들어 특정 그룹의 사용자는 어떤 기능을 사용하지 못하는 경우가 있는데, 이러한 작업들은 컨트롤러로 넘어가기 전에 검사해야 하므로 인터셉터가 처리하기에 적합하다.
Spring 레벨에서 지원하는 Servlet Filter 이기 때문에, 스프링의 모든 빈 객체에 접근할 수 있다.
인터셉터는 여러 개를 사용할 수 있고 로그인 체크, 권한 체크, 프로그램 실행 시간 계산작업 로그 확인 등의 업무처리에 사용한다.참고
'Spring' 카테고리의 다른 글
Spring의 주요 디자인 패턴 (0) 2023.04.17 Spring 빈 스코프(Bean Scope) - 싱글톤, 프로토타입 (0) 2023.03.30 Open EntityManager In View 필터 (0) 2023.02.14 Spring의 @EventListener (0) 2023.01.30 Entity와 DTO 분리하기 (0) 2023.01.25