[F-Lab 멘토링 학습]

스프링 필터와 인터셉터 그리고 차이점

everydeveloper 2023. 9. 26. 20:39

스프링 필터와 인터셉터 그리고 차이점

스프링 필터

스프링 필터

스프링 필터(Spring Filter)는 웹 애플리케이션에서 HTTP 요청이나 응답을 가로채서 추가적인 처리를 할 수 있게 해주는 구성 요소입니다. 필터는 주로 인증, 로깅, 데이터 변환, 인코딩 등 다양한 목적으로 사용됩니다. 서블릿 필터(Servlet Filter)와 마찬가지로 동작하나, 스프링의 라이프사이클과 통합되어 더 다양한 기능을 제공합니다.

필터의 주요 책임:

  1. 인증과 권한 확인: 필터를 통해 사용자의 신원을 확인하고, 특정 리소스에 대한 접근을 제어할 수 있습니다.
  2. 로깅과 모니터링: HTTP 요청이나 응답을 로깅하여 나중에 분석하거나 모니터링할 수 있습니다.
  3. 데이터 가공: 요청이나 응답의 헤더나 본문을 수정하거나 새로운 속성을 추가할 수 있습니다.

스프링에서 필터를 구현하는 방법:

  1. Servlet API를 이용한 구현: Java의 기본적인 javax.servlet.Filter 인터페이스를 구현합니다.
  2. 스프링 제공 필터 클래스 확장: GenericFilterBean, OncePerRequestFilter 등 스프링이 제공하는 필터 클래스를 상속받아 구현할 수 있습니다.
  3. 스프링 시큐리티와의 통합: 스프링 시큐리티는 여러 가지 보안 관련 필터를 제공합니다.

간단한 필터 구현 예제:

public class CustomFilter extends GenericFilterBean {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        // 여기에 로직을 구현합니다.
        chain.doFilter(request, response);
    }
}

필터 등록:

스프링 부트를 사용하는 경우 FilterRegistrationBean을 사용해서 필터를 등록할 수 있습니다.

@Bean
public FilterRegistrationBean<CustomFilter> loggingFilter() {
    FilterRegistrationBean<CustomFilter> registrationBean = new FilterRegistrationBean<>();
    registrationBean.setFilter(new CustomFilter());
    registrationBean.addUrlPatterns("/api/*");
    return registrationBean;
}

이렇게 하면 "/api/*" 경로로 들어오는 모든 요청에 CustomFilter가 적용됩니다.

스프링 필터는 매우 유연하고 확장 가능하기 때문에 다양한 상황에 적응할 수 있습니다. 필터 체인을 구성하여 여러 필터를 순차적으로 적용할 수도 있습니다. 이러한 기능은 웹 애플리케이션의 보안이나 성능 최적화에 매우 유용합니다.

필터 체인:

스프링에서는 여러 필터를 하나의 체인으로 구성할 수 있습니다. 이를 통해 특정 요청에 대해 여러 가지 처리를 순차적으로 할 수 있습니다. 필터 체인은 정의된 순서대로 실행되며, 하나의 필터가 작업을 완료하면 다음 필터로 넘어갑니다.

예외 처리:

필터에서 예외가 발생한 경우, 스프링은 예외 처리 메커니즘을 제공하여 이를 적절히 처리할 수 있습니다. 예를 들어, FilterChain의 doFilter 메소드 내에서 예외를 발생시킬 경우 이를 전역 예외 핸들러로 넘겨 처리할 수 있습니다.

테스트:

필터는 애플리케이션의 중요한 부분이므로 테스트가 필요합니다. 스프링은 MockMvc를 통해 필터에 대한 테스트를 쉽게 수행할 수 있게 도와줍니다.

실용적인 사용 사례:

  1. JWT 토큰 검증: API 요청을 할 때 JWT 토큰의 유효성을 검증하는 필터를 구현할 수 있습니다.
  2. API 레이트 제한: 특정 시간 동안의 요청 횟수를 제한하여 서버에 대한 과부하를 막을 수 있습니다.
  3. CORS 설정: 다른 도메인에서의 요청을 허용하거나 제한하는 설정을 할 수 있습니다.

고려 사항:

  • 필터가 너무 많거나 복잡하면 애플리케이션의 성능에 부정적인 영향을 줄 수 있으므로, 필요한 로직만을 최적화하여 구현해야 합니다.
  • 필터에서의 로직은 가능하면 빠르게 처리되어야 합니다. 긴 작업을 수행해야 한다면 비동기 처리를 고려해야 할 수 있습니다.

스프링 필터는 매우 강력한 도구로, 애플리케이션의 다양한 측면을 향상시킬 수 있습니다. 그러나 이를 효율적으로 사용하기 위해서는 해당 필터가 어떤 목적으로 사용되는지, 어떤 문제를 해결하려고 하는지 정확히 이해할 필요가 있습니다. 이를 통해 필터를 더 효과적으로 설계하고 구현할 수 있습니다.

AOP(Aspect-Oriented Programming)와의 관계:

스프링 필터와 AOP는 비슷한 목적으로 사용될 수 있습니다. AOP는 특정 로직을 여러 부분에 적용할 수 있도록 도와주는 프로그래밍 패러다임입니다. 예를 들어, 로깅, 트랜잭션 관리, 보안 등이 있습니다. 필터는 주로 웹 계층에서 사용되는 반면, AOP는 어플리케이션의 여러 계층에 걸쳐 사용될 수 있습니다. 각기 장단점과 적용 케이스가 있으므로, 상황에 따라 적절한 것을 선택해야 합니다.

스프링 부트와의 통합:

스프링 부트는 자동 설정(auto-configuration)을 통해 필터를 쉽게 추가할 수 있습니다. 예를 들어, 스프링 부트의 시큐리티 스타터를 사용하면 기본적인 웹 보안 필터가 자동으로 설정됩니다.

성능 최적화:

  • 캐싱: 필터를 사용하여 자주 사용되는 데이터나 결과를 캐시에 저장할 수 있습니다. 이렇게 하면 서버의 부하를 줄이고 응답 시간을 개선할 수 있습니다.
  • GZIP 압축: 응답 데이터의 크기를 줄이기 위해 GZIP 압축을 사용할 수 있습니다. 이는 네트워크 대역폭을 절약하는 데 도움이 됩니다.

디버깅과 트러블슈팅:

필터가 복잡해지면 디버깅이 어려울 수 있습니다. 이런 경우 로깅을 통해 문제를 진단할 수 있습니다. 스프링 부트는 logging.level 프로퍼티를 통해 로깅 레벨을 설정할 수 있습니다.

마치며:

스프링 필터는 HTTP 요청과 응답을 중간에서 가로채 처리할 수 있는 강력한 도구입니다. 여러 필터를 체인으로 연결하여 복잡한 로직을 구현할 수도 있습니다. 하지만 그만큼 주의 깊게 설계와 구현을 해야 합니다. 또한, 필터와 AOP 등 다른 스프링의 기능과 어떻게 통합될 수 있는지도 이해하는 것이 중요합니다. 이를 통해 더 효율적이고 유지보수가 쉬운 애플리케이션을 구축할 수 있습니다.

유지보수와 확장성:

스프링 필터는 잘 설계되면 유지보수와 확장성 측면에서도 이점을 가져다 줍니다. 예를 들어, 중복되는 로직을 필터로 추상화하면 여러 컨트롤러나 서비스에서 중복 코드를 제거할 수 있습니다. 이렇게 하면 코드의 일관성을 유지하면서 새로운 기능을 쉽게 추가할 수 있습니다.

프로덕션에서의 모니터링:

프로덕션 환경에서는 필터를 통한 로깅 및 모니터링이 중요합니다. 이를 통해 실시간으로 애플리케이션의 상태를 확인하거나, 문제가 발생했을 때 신속하게 대응할 수 있습니다. 예를 들어, AWS CloudWatch나 Prometheus와 같은 모니터링 도구를 통합할 수 있습니다.

테스트 전략:

필터의 로직이 복잡해질수록, 그에 따른 테스트 케이스도 복잡해질 가능성이 있습니다. 단위 테스트와 통합 테스트를 적절히 조합하여 필터의 기능을 철저히 검증해야 합니다.

보안 측면:

필터에서 자주 다루는 보안 관련 이슈에는 SQL 인젝션, XSS, CSRF 등이 있습니다. 스프링 시큐리티와 같은 라이브러리를 사용하면 이러한 보안 이슈를 효과적으로 해결할 수 있습니다.

마이크로서비스와의 통합:

마이크로서비스 아키텍처에서는 API 게이트웨이를 사용하여 여러 마이크로서비스를 통합할 수 있습니다. API 게이트웨이에서 필터를 사용하면, 모든 마이크로서비스에 공통적으로 적용되어야 하는 로직을 중앙에서 관리할 수 있습니다.

결론:

스프링 필터는 다양한 웹 애플리케이션 요구사항을 충족시키는 강력한 도구입니다. 그러나 그만큼 주의깊은 설계와 구현, 그리고 테스트 전략이 필요합니다. 필터의 적절한 활용을 통해 성능, 보안, 유지보수성 등 다양한 측면에서 애플리케이션을 향상시킬 수 있습니다. 이러한 지식과 실무 경험을 바탕으로 더욱 견고하고 확장 가능한 시스템을 구축하게 될 것입니다.

동시성과 스레딩:

스프링 필터는 동시에 여러 요청을 처리할 수 있어야 하므로, 동시성 관리가 중요합니다. 스레드 로컬 변수나 동기화 메커니즘을 적절히 사용하여 동시성 문제를 해결할 수 있습니다.

커스터마이징과 확장:

스프링은 필터 인터페이스를 직접 구현할 수 있도록 지원하며, 이를 통해 특정 비즈니스 로직에 맞게 필터를 커스터마이즈 할 수 있습니다. 이를 통해 특정 조건에 따라 동적으로 필터를 적용하거나 제거할 수 있습니다.

그룹핑과 정렬:

복수의 필터가 있다면, 어떤 순서로 실행될지, 어떤 필터가 그룹으로 묶일지를 잘 정해야 합니다. 이는 @Order 또는 Ordered 인터페이스를 사용하여 설정할 수 있습니다.

비동기 처리:

비동기 작업이 필요한 경우, AsyncContext를 사용해서 비동기 작업을 처리할 수 있습니다. 이렇게 하면 웹 컨테이너의 스레드를 더 효율적으로 사용할 수 있습니다.

스프링 클라우드와의 시너지:

스프링 클라우드 환경에서는 Zuul이나 Spring Cloud Gateway를 사용하여 라우팅 및 필터링을 수행할 수 있습니다. 이런 컴포넌트들은 분산 시스템에서 필터를 쉽게 관리하게 도와줍니다.

코드 리뷰와 문서화:

어떠한 코드도 완벽하지 않기 때문에 코드 리뷰 과정에서는 필터의 로직과 성능에 대한 평가가 이루어져야 합니다. 또한, 필터의 동작 방식, 설정, 예외 케이스 등에 대한 문서화는 후반 작업에서 큰 도움이 됩니다.

최종 생각:

스프링 필터는 강력하면서도 복잡한 컴포넌트입니다. 올바르게 사용될 경우, 성능 최적화, 보안 강화, 코드 재사용성 향상 등 다양한 이점을 제공할 수 있습니다. 하지만, 잘못 구현된 필터는 시스템 전체에 문제를 일으킬 수 있으므로 주의가 필요합니다. 따라서 계획적인 설계, 철저한 테스트, 그리고 지속적인 모니터링과 리팩토링이 필요합니다. 이러한 노력을 통해 더욱 견고하고 확장 가능한 애플리케이션을 만들 수 있을 것입니다.

에러 핸들링과 예외 처리:

스프링 필터에서는 특별히 에러 핸들링과 예외 처리에 대한 고려가 필요합니다. 필터 내에서 발생하는 예외는 컨트롤러나 서비스 계층으로 전파되지 않을 수 있으므로, 적절한 에러 응답을 클라이언트에게 반환해야 할 필요가 있습니다.

의존성 주입(DI):

스프링의 DI(Dependency Injection) 기능을 활용하여 필터 내부에서 다른 스프링 빈을 주입받을 수 있습니다. 이를 통해 서비스 로직을 호출하거나, 다른 유틸리티 클래스에 접근할 수 있습니다. 하지만 주의할 점은, 필터는 스프링 라이프사이클의 초기 단계에서 초기화되므로, 빈 생성 순서에 따라 의존성 주입이 제대로 이루어지지 않을 수도 있습니다.

세션과 쿠키 관리:

HTTP는 상태를 유지하지 않는 프로토콜이므로, 필터에서 세션 또는 쿠키를 통해 상태 정보를 관리할 수 있습니다. 이러한 기능은 주로 사용자 인증, 쇼핑 카트, 트랙킹 등에 활용됩니다.

CDN과 캐싱 전략:

클라이언트 측 캐싱과 CDN(Content Delivery Network)을 활용하려면, 필터에서 캐싱 헤더를 적절하게 설정해야 합니다. 이는 클라이언트와 CDN이 리소스를 얼마나 오래 캐싱할지 결정하는데 도움을 줍니다.

로드 밸런싱과 분산:

필터를 사용하여 로드 밸런싱 알고리즘을 구현할 수도 있습니다. 예를 들어, 특정 IP 범위의 사용자에게는 다른 서버로 요청을 라우팅할 수 있습니다. 하지만 이러한 로직은 대체로 더 특화된 로드 밸런서나 API 게이트웨이에서 처리하는 것이 일반적입니다.

코드 재사용과 모듈화:

필터 로직이 여러 프로젝트에서 공통으로 사용되는 경우, 별도의 라이브러리로 분리하여 모듈화할 수 있습니다. 이렇게 하면 코드 재사용성을 높이고, 버전 관리도 용이해집니다.

스프링 필터는 웹 애플리케이션에서 중요한 역할을 하는 컴포넌트입니다. 특히 대규모, 복잡한 애플리케이션에서는 필터의 역할이 더욱 중요해집니다. 따라서 실무에서는 위에서 언급한 다양한 측면을 고려하여 스프링 필터를 설계하고 구현해야 합니다. 이를 통해 효율적이고 안정적인 웹 서비스를 제공할 수 있을 것입니다.

스프링 부트 초기의 필터 설정

스프링 부트에서는 몇몇 기본적인 필터가 자동으로 설정됩니다. 예를 들어, 보안을 위한 필터, 캐싱, HTTP 요청과 응답에 대한 로깅 등을 기본적으로 제공할 수 있습니다. 이러한 필터는 대부분의 경우 자동으로 활성화되며, 필요에 따라 추가 설정이나 커스터마이징을 할 수 있습니다.

스프링 부트의 자동 설정은 편리함을 제공하지만, 모든 상황에 적합한 것은 아닙니다. 따라서 특별한 요구사항이 있을 경우, 자동 설정을 비활성화하고 필터를 직접 구성할 수 있습니다. application.properties나 application.yml 파일, 또는 Java Config를 사용하여 이러한 설정을 변경할 수 있습니다.

예를 들어, 스프링 부트의 자동 설정을 통해 스프링 시큐리티가 활성화되면, 기본적으로 몇 가지 보안 관련 필터가 자동으로 적용됩니다. 이를 커스터마이즈하거나 비활성화하려면, 스프링 시큐리티의 설정을 오버라이딩해야 할 수 있습니다.

결론적으로, 스프링 부트는 개발의 편의성을 위해 몇몇 기본 필터를 자동으로 설정하지만, 이것이 모든 상황에 적합하다고는 할 수 없습니다. 따라서 필요에 따라 이러한 설정을 변경하거나, 새로운 필터를 추가하는 것이 가능합니다.

스프링 시큐리티와 필터

스프링 시큐리티(Spring Security)는 사실상 일련의 필터로 구성되어 있습니다. 스프링 시큐리티는 인증(Authentication)과 권한 부여(Authorization)를 처리하기 위한 다양한 필터를 제공하며, 이러한 필터들은 보통 FilterChain 내에서 정의된 순서대로 실행됩니다.

스프링 시큐리티의 주요 필터 몇 가지를 예로 들자면,

  • UsernamePasswordAuthenticationFilter: 사용자 이름과 비밀번호를 통한 인증을 처리합니다.
  • JwtAuthenticationFilter: JWT(Json Web Token)를 이용한 인증을 처리합니다.
  • BasicAuthenticationFilter: HTTP Basic 인증을 처리합니다.
  • CsrfFilter: CSRF(Cross-Site Request Forgery) 공격을 방어합니다.
  • LogoutFilter: 로그아웃 요청을 처리합니다.

등이 있습니다.

이러한 필터들은 대부분 WebSecurityConfigurerAdapter 클래스를 상속받아서 커스터마이징할 수 있습니다. 예를 들어, configure(HttpSecurity http) 메서드 내에서 .addFilterBefore(), .addFilterAfter() 같은 메서드를 사용하여 필터의 순서를 변경할 수 있습니다.

이 필터들은 보통 HTTP 요청이 들어왔을 때 그 요청이 어떤 권한을 가지고 있는지 검사하고, 해당 요청이 애플리케이션의 어떤 리소스에 접근할 수 있는지를 결정합니다. 따라서 스프링 시큐리티는 그 자체로도 매우 강력한 필터 기능을 수행하며, 웹 애플리케이션의 보안을 강화하는 데 아주 중요한 역할을 합니다.

인터셉터

인터셉터(interceptor)는 클라이언트와 서버 간의 요청과 응답을 가로채서 처리하는 구조입니다. 이러한 인터셉터는 주로 로깅, 인증, 데이터 변환 등을 수행할 때 사용됩니다. 아래에는 인터셉터의 사용법과 활용 케이스에 대한 자세한 설명이 있습니다.

사용하는 기술 스택에 따른 인터셉터의 종류:

  1. Spring (Java): HandlerInterceptor 인터페이스를 구현해서 사용합니다.
  2. Express (Node.js): 미들웨어 함수를 사용합니다.
  3. Angular (TypeScript): HttpInterceptor 인터페이스를 구현합니다.
  4. Django (Python): 미들웨어를 사용합니다.

주요 역할:

  1. 로깅: 요청과 응답 데이터를 로깅하여 디버깅을 용이하게 합니다.
  2. 인증: 토큰이나 세션을 검증하여 접근 권한을 체크합니다.
  3. 데이터 변환: 요청이나 응답 데이터의 포맷을 변경합니다. 예를 들어, XML을 JSON으로 변환할 수 있습니다.
  4. 에러 핸들링: 에러를 중앙에서 처리하여 일관된 에러 응답을 생성합니다.

예시 (Spring Boot에서의 Java):

@Component
public class MyInterceptor extends HandlerInterceptorAdapter {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 요청 전처리
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
        // 요청 후처리
    }
}

예시 (Node.js에서의 Express):

app.use((req, res, next) => {
    // 요청 전처리
    next();
});

예시 (Angular에서의 TypeScript):

@Injectable()
export class MyInterceptor implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    // 요청 처리
    return next.handle(req);
  }
}

AWS와의 연계

AWS 환경에서도 인터셉터는 유용하게 사용될 수 있습니다. 예를 들어, AWS Lambda로 서버리스 애플리케이션을 구성할 때 API Gateway에서 인터셉터와 유사한 로직을 미들웨어로 구현할 수 있습니다.

성능 최적화

인터셉터를 활용하면 캐시, 압축 등을 통해 애플리케이션 성능을 향상시킬 수 있습니다. 예를 들어, ETag 또는 Last-Modified 헤더를 사용하여 리소스 변경 여부를 판단하고, 변경되지 않았다면 캐시된 데이터를 반환할 수 있습니다.

로드 밸런싱

특히 클라우드 환경에서 로드 밸런서를 앞단에 두고 여러 서버에 분산되는 요청을 가로채서 특정 조건에 따라 분산시킬 수 있습니다.

A/B 테스팅

인터셉터는 사용자에게 서로 다른 버전의 서비스를 제공하여 A/B 테스팅을 진행하는 데도 사용될 수 있습니다.

모니터링 및 분석

AWS CloudWatch와 같은 모니터링 툴과 연계하여 API 사용 패턴, 에러율, 응답 시간 등을 실시간으로 모니터링할 수 있습니다.

트랜잭션 관리

데이터베이스 트랜잭션을 다룰 때 인터셉터를 사용하면 트랜잭션의 시작과 종료를 더욱 명확하게 관리할 수 있습니다.

Spring Boot에서의 사용법 확장

Spring Boot에서는 Java Config를 사용하여 인터셉터를 등록할 수 있습니다.

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private MyInterceptor myInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(myInterceptor);
    }
}

에러 처리와 예외 관리

Spring Boot의 경우 HandlerExceptionResolver를 통해 중앙에서 예외를 처리할 수 있습니다. 인터셉터 내에서 발생하는 예외를 캐치하여 적절한 에러 메시지와 함께 클라이언트에게 응답을 전달할 수 있습니다.

인터셉터 체이닝

인터셉터는 여러 개를 등록해서 사용할 수 있으며, 등록된 순서대로 실행됩니다. 이러한 방식을 통해 로깅, 인증, 데이터 변환 등 여러 가지 작업을 순차적으로 처리할 수 있습니다.

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(loggingInterceptor);
    registry.addInterceptor(authenticationInterceptor);
    registry.addInterceptor(dataTransformInterceptor);
}

멀티테넌시(Multi-Tenancy) 환경

멀티테넌시는 여러 테넌트가 하나의 애플리케이션 인스턴스를 공유하는 구조입니다. 인터셉터를 사용하면 요청 헤더나 URL로부터 테넌트 정보를 추출해 해당 테넌트에 맞는 로직을 실행할 수 있습니다.

레이트 리밋

API 요청에 대한 레이트 리밋을 적용하려면 인터셉터에서 클라이언트의 IP 주소나 사용자 ID를 추출하여 요청 횟수를 제한할 수 있습니다. 이러한 로직은 AWS API Gateway에서도 설정할 수 있지만, 커스텀 로직이 필요한 경우에는 직접 인터셉터에서 처리할 수 있습니다.

AWS 서비스와의 시너지

AWS SAA 인증을 보유하고 있으므로, 예를 들어 Amazon API Gateway의 custom authorizer나 Lambda 함수로도 인터셉터와 유사한 기능을 구현할 수 있습니다. 또한, 이러한 로직을 AWS CloudFormation 템플릿에 포함시켜 자동화도 가능합니다.

인터셉터는 요청과 응답을 가로채는 강력한 메커니즘이며, 그 활용 범위는 매우 다양합니다. AWS 환경에서는 서버리스 아키텍처, 레이트 리밋, 로깅 등 다양한 영역에서 인터셉터와 유사한 기능을 구현할 수 있습니다.

더 궁금한 점이나 추가적인 설명이 필요하시면 언제든지 문의해 주세요. 감사합니다!

스프링 필터와 인터셉터의 차이점

스프링 필터와 인터셉터의 차이점

스프링 프레임워크에서 필터와 인터셉터는 비슷한 역할을 하지만 몇 가지 중요한 차이점이 있습니다. 두 개념의 차이점에 대해 자세히 알아보겠습니다.

실행 시점

  1. 필터(Filter): 디스패처 서블릿에 들어가기 전에 실행됩니다. 즉, 모든 요청에 대해 가장 먼저 실행되며, HTTP 요청과 응답 자체에 대한 처리를 할 수 있습니다.
  2. 인터셉터(Interceptor): 디스패처 서블릿이 컨트롤러를 호출하기 전후로 실행됩니다. 스프링의 컨텍스트(Context) 내에서 동작하기 때문에 스프링 빈을 이용한 다양한 작업이 가능합니다.

기능

  1. 필터: HTTP 요청과 응답에 대한 기본적인 처리가 가능합니다. 인코딩, 보안, 로깅 등을 할 수 있습니다.
  2. 인터셉터: 뷰를 렌더링하기 전후의 액션, 컨트롤러의 처리 전후의 액션 등 스프링의 라이프사이클에 더 밀접하게 연관된 작업을 수행할 수 있습니다.

설정

  1. 필터: web.xml에 설정하거나 Java Config를 사용하여 설정합니다.
  2. 인터셉터: 스프링의 Java Config에서 WebMvcConfigurer를 구현하여 설정합니다.

스프링 빈 접근

  1. 필터: 스프링 빈에 접근하기 어렵습니다. 필터는 스프링 애플리케이션 컨텍스트 밖에서 동작하기 때문입니다.
  2. 인터셉터: 스프링의 애플리케이션 컨텍스트 안에서 동작하므로 스프링 빈에 쉽게 접근할 수 있습니다.

예제

  • 필터 예제
  • public class MyFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) { // 로직 처리 chain.doFilter(request, response); } }
  • 인터셉터 예제
  • public class MyInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { // 로직 처리 return true; } }

필터와 인터셉터는 각기 다른 목적과 활용도를 가지고 있으므로, 상황에 따라 적절한 것을 선택하여 사용하면 됩니다. 스프링의 라이프사이클과 관련된 더 복잡한 처리가 필요하다면 인터셉터를, HTTP 요청과 응답에 대한 전처리가 주목적이라면 필터를 사용하면 좋습니다.

테스트 용이성

  1. 필터: 테스트하기가 상대적으로 복잡할 수 있습니다. 일반적으로 서블릿 컨테이너가 필요하기 때문에 Mock 객체를 사용해야 할 수도 있습니다.
  2. 인터셉터: 스프링 컨텍스트에서 동작하기 때문에, 스프링의 테스트 프레임워크를 활용하여 비교적 쉽게 테스트할 수 있습니다.

대상 리소스

  1. 필터: 정적 리소스에 대한 필터링도 수행합니다. 즉, HTML, 이미지, CSS 파일 등도 대상이 될 수 있습니다.
  2. 인터셉터: 주로 컨트롤러 메서드에 대한 요청만을 대상으로 합니다.

예외 처리

  1. 필터: 서블릿 수준에서 예외를 처리하므로 전역 예외 처리가 어렵습니다.
  2. 인터셉터: 스프링의 HandlerExceptionResolver를 이용하여 중앙에서 예외 처리가 가능합니다.

실행 순서

  1. 필터: 다른 필터나 서블릿과의 실행 순서를 정확하게 제어하기 어렵습니다.
  2. 인터셉터: 정확한 실행 순서를 지정할 수 있어, 다른 인터셉터나 스프링 컴포넌트와의 조화를 이루기 쉽습니다.

사용 사례

  1. 필터: 인증, 로깅, CORS 설정, 인코딩 등 HTTP 수준에서 필요한 공통 처리 작업에 주로 사용됩니다.
  2. 인터셉터: 인증 뿐만 아니라, 로깅, 데이터 변환, 사용자 세션 확인, 메서드 실행 시간 측정 등 다양한 스프링 내부의 로직을 수행할 때 사용됩니다.

최적의 선택 기준

  • 필터: 애플리케이션에 독립적인, 재사용 가능한 로직을 구현할 때 유용합니다.
  • 인터셉터: 스프링의 기능과 더 밀접하게 연관된 로직, 또는 스프링 빈과의 상호작용이 필요할 때 유용합니다.

필터와 인터셉터는 각각의 장단점과 특성이 있으므로, 어떤 작업을 수행해야 하는지, 그리고 그 작업이 어떤 레벨에서 이루어져야 하는지를 고려하여 적절한 선택을 해야 합니다. 더 깊은 내용이나 구체적인 상황에 대한 질문이 있으면 언제든지 물어보세요. 감사합니다!

필터와 인터셉터의 동작/관리 계층

필터

  • 관리 주체: 필터는 톰캣, 제티, 언더토우 등의 서블릿 컨테이너나 어플리케이션 서버가 관리합니다.
  • 동작 계층: 필터는 서블릿 컨테이너 레벨에서 동작하므로, 웹 애플리케이션에 들어오는 모든 HTTP 요청과 응답에 대한 처리가 가능합니다.
  • 스코프: 필터는 어플리케이션 전체, 즉 서블릿 컨텍스트 전체에 걸쳐 동작할 수 있습니다.

인터셉터

  • 관리 주체: 인터셉터는 스프링 프레임워크가 관리합니다.
  • 동작 계층: 인터셉터는 디스패처 서블릿이 컨트롤러를 호출하기 전, 후에 동작합니다. 따라서 스프링의 MVC 프레임워크와 밀접하게 연결됩니다.
  • 스코프: 스프링의 애플리케이션 컨텍스트 내에서 동작하므로 스프링 빈에 쉽게 접근할 수 있고, 스프링의 다양한 기능을 활용할 수 있습니다.

이러한 차이점 때문에 필터와 인터셉터의 적용 시나리오나 사용 목적도 다르게 됩니다. 필터는 애플리케이션 전체에 영향을 미치는 공통 로직을 처리하는 데 적합하며, 인터셉터는 스프링 MVC의 특정 컨트롤러나 액션에 대한 로직을 수행하는 데 더 적합합니다.