필터(Filter)

  • Filter 는 클라이언트의 요청을 중간에 가로챈다.
  • 요청과 응답 (Request & Response) 를 가로챌 수 있다.
  • Filter 가 요청과 응답을 가로채는 동안에 서블릿은 이를 확인할 수 없다.
  • Filter 는 일반적인 자바 컴포넌트이다.
  • Filter 는 요청과 응답에 대해서 아래와 같은 처리를 하면 유용하다.
    • Request Filter
      • 보안 관련 내용 체크
      • 요청 헤더와 바디 포맷팅을 수정
      • 요청을 감시하고 기록화
    • Response Filter
      • 응답 스트림을 압축
      • 응답 스트림에 내용을 추가하거나 수정
      • 새로운 응답 생성

 

컨테이너가 필터의 생명주기를 관리한다. 따라서 서블릿과 동일한 메소드가 존재하고 이에 맞게 동일한 순서로 수행된다. 가령 필터를 인스턴스화 하기 위해서 init() 메소드를 호출하기 때문에, 필터가 호출되기 전에 뭔가 설정할 것이 있다면 여기서 수행하여야 한다. 이후에 doFilter() 메소드를 수행하여 요청이나 응답을 중간에 가로채고 사용자가 정의한 로직을 수행할 수 있다. 마지막으로 컨테이너가 필터 인스턴스를 제거하기 위해 destory() 메소드를 호출하고 마무리된다.

 

사실상 Filter 는 doFilter() 메소드가 가장 많은 일을 수행한다.

 

Filter Sample Code

public class DemoFilter implements Filter {

    private FilterConfig config;

    /**
     * 컨테이너가 필터를 인스턴스화 한다.
     * @param filterConfig
     * @throws ServletException
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("init()");
        this.config = filterConfig;
    }

    /**
     * 필터의 기능을 수행한다.
     * @param servletRequest
     * @param servletResponse
     * @param filterChain
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("doFilter()");
    
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
    
        String name = httpServletRequest.getRemoteUser();
    
        if(name != null){
            config.getServletContext().log("User : " + name + "is Updating");
        }
    
        filterChain.doFilter(servletRequest, servletResponse);
    }

    /**
     * 컨테이너가 필터 인스턴스를 제거한다.
     */
    @Override
    public void destroy() {
        System.out.println("destroy()");
    }
}

 

  • 컨테이너가 현재 사용자의 요청에 대해서 필터를 적용해야겠다고 판단하면 doFilter() 메소드를 호출한다.
  • doFilter() 메소드는 3개의 인자를 받는다.
    • ServletRequest/ ServletResponse/ FilterChain 
    • ServletRequest 와 ServletResponse 는 HttpServletRequest 와 HttpServletResponse 가 아니다.

여기서 좀 더 유심히 살펴볼 부분이 있다.

  • Filter interface
  • FilterChain interface

Filter interface

package javax.servlet;

import java.io.IOException;

public interface Filter {
    void init(FilterConfig var1) throws ServletException;

    void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;

    void destroy();
}

 

FilterChain interface

package javax.servlet;

import java.io.IOException;

public interface FilterChain {
    void doFilter(ServletRequest var1, ServletResponse var2) throws IOException, ServletException;
}

 

두 인터페이스를 살펴보면 받는 인자의 개수가 다르다. 결론부터 말하면 Filter interface 의 doFilter() 메소드는 실질적으로 요청과 응답에 대해서 필터링 작업을 수행하는 메소드이다. 반면에 FilterChain interface 의 doFilter() 메소드는 이후에 호출할 필터가 무엇인지 파악하고 해당 필터의 doFilter() 메소드를 호출한다.

 

  • FilterChain interface 의 doFilter() : 이후에 쌓여있는 필터의 doFilter() 메소드를 수행한다.
  • Filter interface 의 doFilter() : 실질적인 필터링 작업을 수행한다.

FilterChain 의 doFilter() 에 다음 수행할 필터가 존재하지 않다면? 

  • 서블릿의 service() 메소드를 호출한다.

필터는 스택과 같이 쌓을 수 있다. 

 

스택이라고 한다면 흔히 우리들 LIFO 개념으로 알고있는데 정말 그렇다.

 

만약에 사용자의 요청 Request A 가 들어왔다면 해당 A 요청은 여러 개의 필터를 타고 이후에 서블릿의 service() 메소드를 호출할 것이다. 그리고 service() 로직이 완료된 이후에 응답 또한 A 요청이 들어왔던 방식 반대로 여러 개의 Filter 를 다시 타면서 필터링 될 것이다.

 

reference

헤드퍼스트 디자인 패턴 : Servlet & JSP

Posted by doubler
,