Spring

Spring - Filter

jaewoo 2023. 3. 30. 16:51

 

1. Filter

필터는 말 그대로 요청과 응답을 정제하는 역할을 한다. DispatcherServlet에 요청이 들어가기 전에 만나면서 서버에서 응답이 마지막에 만나는 곳이기도 하다. 

즉, 스프링 컨테이너가 아닌 톰캣과 같은 컨테이너에서 관리가 되는 것이고, 스프링 범위 밖에서 처리되는 것이다.

 

여기서 의문이 들어서 글들을 찾아봤다. 

 

스프링 범위 밖이라는 것은 스프링에서 관리를 하지 못한다는 것이고 빈으로도 당연히 등록하지 못할텐데 어떻게 빈으로 등록할 수 있는거지? 

답은

https://mangkyu.tistory.com/221

 

[Spring] 필터(Filter)가 스프링 빈 등록과 주입이 가능한 이유(DelegatingFilterProxy의 등장) - (2)

몇몇 포스팅과 조금 오래된 책들을 보면 필터(Filter)는 서블릿 기술이라서 Spring의 빈으로 등록할 수 없으며 빈을 주입받을수도 없다는 내용이 나옵니다. 하지만 실제로 테스트를 해보면 Filter 역

mangkyu.tistory.com

여기 있었는데  DelegatingFilterProxy의 등장 전과 후 그리고 스프링 부트의 등장 이렇게 나뉘어진다.

 

- DelegatingFilterProxy가 등장이전에는  Filter가 서블릿 컨테이너에 의해 생성되며 컨테이너에 등록이 된다. 그렇기 때문에 빈으로도 등록이 불가능했 던게 맞았다. 등록이 불가능하기에 주입도 불가능했지만 Filter가 주입 받을 일이 필요해지면서 대안을 마련했는데 그것이 DelegatingFilterProxy이다.

- DelegatingFilterProxy가 나오면서 Servlet Filter 역시 스프링에서 관리가 가능해졌다. 여기서 DelegatingFilterProxy는 톰캣에서 관리되는 프록시용 Filter로 스프링에서 정의한 필터를 가지고 있다. 정의한 필터들은 IOC에 빈으로 등록되는데, 서버에 요청이 들어오면 DelegatingFilterProxy가 요청을 받아서 정의한 Filter에게 요청을 위임하는 식으로 변경되었다.

      정리하면 

         

1. FIlter 구현체가 스프링 빈으로 등록됨
2. ServletContext(톰캣)가 Filter 구현체를 가지고 있는 프록시(DelegatingFIlterProxy)를 생성함
3. ServletContext가 프록시를 서블릿 컨테이너에 필터로 등록함
4. 서버에 요청이 오면 프록시가 필터 구현체에게 요청을 위임하여 필터 처리를 진행함

 

- 스프링 부트 등장

SpringBoot는 DelegatingFilterProxy가 필요없다. 부트는 내장 웹서버를 지원하면서 톰캣과 같은 서블릿 컨테이너까지 부트가 제어가 가능해졌기 떄문이다. 그러므로 Filter를 DelegatingFilterProxy로 감싸서 등록하지 않아도 된다. boot가 Servlet Filter 구현체 빈을 찾으면 DelegatingFilterProxy 없이 바로 Filter Chain에 필터를 등록해주기 때문이다.

 

 

Servlet Filter 구현체를 만들려면 Filter 인터페이스를 구현해야한다. Filter 인터페이스에는 세 개의 메서드가 선언되어 있다. 

- init 메서드

    Application이 실행되면서 Servlet Filter를 초기화한다. 해당 과정에서 Servlet Filter의 init() 메서드를 실행한다. 해당 메소드에는 내부로직을 초기화 하는 기능을 구현하면 좋다. 

- doFilter 

   요청마다 실행되는 메소드로 Servlet Filter의 핵심 기능을 구현하면 된다.

- destory 

    Application을 종료하면 Servlet Filter도 같이 종료되는데 해당 과정에서 destroy 메서드를 실행한다.

 

   public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException;

해당 doFilter가 가장 중요한데 해당 메소드는 ServeltRequest, ServletResponse, FilterChain을 인자로 받는다. 해당 인자들을 통해 클라이언트의 요청, 응답 데이터를 참조하거나 가공할 수 있다. 여기서 주의할 점은 데이터가 휘발성이다. request.getInputStream 으로 읽을시 데이터가 손실된다. FilterChain은 doFilter()메소드를 호출하면 다음 Filter 로 이동하거나 Filter가 없다면 DispatcherServlet으로 요청이 이동한다. 그렇기 때문에 반드시 요청 처리가 끝나면 doFilter메소드를 실행시켜야한다. 안 그러면 다음으로 넘어가지 못한다.

 

public class CustomFilter implements Filter{

        	@Override
            public void doFilter(ServletRequest request,
            					ServletResponse response,
                                FilterChain filterChain){
            	
                	System.out.println("Filter 요청 처리");
                    filterChain.doFilter(request,response);
                    System.out.println("Filter 응답 처리");
             }

}

이렇게 Filter를 구현했다면 Filter를 등록해야하는데 Servlet Container에 Servlet Container의 web.xml에 Servlet Filter를 정의한다. 하지만 부트의 경우 Servlet Filter를 Bean으로 등록할 수 있는 FilterRegistractionBean 클래슬르 제공한다. 설정 클래스에서 Filter를 감싸고 빈으로 등로갛면 된다. 

 

@Configuration
public class WebConfig implements WebMvcConfigurer{

	@Bean
        public FilterRegistrationBean<CustomFilter> filterCustom(){
        	CustomFilter filter = new CustomFilter();
            
            FilterRegistrationBean<CustomFilter> filterBean = new FilterRegistrationBean<>();
            filterBean.setFilter(filter);
            filterBean.setUrlPatterns("*");
            filterBean.setOrder(1);
            return filterBean;
        }

}

 

'Spring' 카테고리의 다른 글

AWS - 배포와 기록(Spring boot)  (0) 2023.04.14
Spring - MockMvc  (0) 2023.04.03
Spring - DispatcherServlet  (0) 2023.02.24
Spring - 작성자 체크하기  (0) 2023.02.09
Spring - AOP,@Transactional  (0) 2023.01.27