Deep Dive /Java Web /5

5. DelegatingFilterProxy → FilterChainProxy.doFilter() → FilterChain 복귀

Spring Security의 실제 Filter 체인 흐름을 오픈소스 코드 근거로 분석합니다.


전체 흐름 요약

  1. Tomcat의 ApplicationFilterChain이 각 Filter의 doFilter()를 호출
  2. Spring Security DelegatingFilterProxy가 등장하면, 내부적으로 Spring의 FilterChainProxy로 위임
  3. FilterChainProxy는 SecurityFilterChain(여러 Security Filter)들을 순차적으로 실행
  4. 모든 Security Filter가 끝나면, 원래의 FilterChain(ApplicationFilterChain)으로 복귀
  5. 남은 Filter가 있으면 계속 진행, 없으면 서블릿으로 이동

실제 코드 흐름 분석

1) Tomcat ApplicationFilterChain

// ApplicationFilterChain.java
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
    if (pos < n) {
        ...
        filter.doFilter(request, response, this); // 다음 Filter 호출
        return;
    }
    // 모든 Filter가 끝나면 서블릿 호출
    ...
}

2) DelegatingFilterProxy

// DelegatingFilterProxy.java
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {
    ...
    invokeDelegate(delegateToUse, request, response, filterChain);
}

protected void invokeDelegate(Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {
    delegate.doFilter(request, response, filterChain); // 실제 FilterChainProxy로 위임
}

3) FilterChainProxy (Spring Security)

// FilterChainProxy.java
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {
    ...
    doFilterInternal(request, response, chain);
}

private void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {
    ...
    this.filterChainDecorator.decorate(reset, filters).doFilter(firewallRequest, firewallResponse);
}

// 내부 VirtualFilterChain
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
    if (this.currentPosition == this.size) {
        this.originalChain.doFilter(request, response); // 모든 Security Filter 끝나면 원래 FilterChain으로 복귀
        return;
    }
    ...
    nextFilter.doFilter(request, response, this); // 다음 Security Filter 호출
}

시퀀스 다이어그램

sequenceDiagram participant FilterChain as ApplicationFilterChain participant SecurityProxy as DelegatingFilterProxy participant SecurityChain as FilterChainProxy participant SecurityFilters as SecurityFilterChain participant Servlet FilterChain->>SecurityProxy: doFilter() SecurityProxy->>SecurityChain: doFilter() SecurityChain->>SecurityFilters: doFilter() (여러 Security Filter) SecurityFilters-->>SecurityChain: 완료 SecurityChain-->>FilterChain: doFilter() (원래 FilterChain 복귀) FilterChain->>Servlet: service()

설계 의도 및 이유

  • Tomcat과 Spring Security의 결합을 느슨하게 유지하기 위해 DelegatingFilterProxy를 사용
  • Spring Security의 FilterChainProxy는 여러 보안 필터를 유연하게 조합/관리
  • 모든 보안 처리가 끝나면, 원래의 FilterChain(ApplicationFilterChain)으로 복귀하여 서블릿 처리 흐름을 보장
  • 이 구조 덕분에 보안 로직과 웹 컨테이너의 결합도가 낮아지고, 확장성과 테스트 용이성이 높아짐

← 이전: 4. ApplicationFilterChain → DelegatingFilterProxy.doFilter() | 다음: 6. (작성 예정)