@@ -0,0 +1,83 @@
+package nextstep.security.config;
+
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.web.filter.GenericFilterBean;
+
+import java.io.IOException;
+import java.util.List;
+
+public class FilterChainProxy extends GenericFilterBean {
+
+    private final List<SecurityFilterChain> filterChains;
+
+    private VirtualFilterChainDecorator virtualFilterChainDecorator = new VirtualFilterChainDecorator();
+
+    public FilterChainProxy(List<SecurityFilterChain> filterChains) {
+        this.filterChains = filterChains;
+    }
+
+    @Override
+    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
+        HttpServletRequest request = (HttpServletRequest) servletRequest;
+        HttpServletResponse response = (HttpServletResponse) servletResponse;
+
+        List<Filter> filters = getFilters(request);
+        
+        if (filters == null || filters.isEmpty()) {
+            filterChain.doFilter(request, response);
+            return;
+        }
+        this.virtualFilterChainDecorator.decorate(filterChain, filters).doFilter(request, response);
+    }
+
+    private List<Filter> getFilters(HttpServletRequest request) {
+        return this.filterChains.stream()
+                .filter(chain -> chain.matches(request))
+                .findAny()
+                .map(SecurityFilterChain::getFilters)
+                .orElse(null);
+    }
+
+    public static final class VirtualFilterChainDecorator {
+
+        public FilterChain decorate(FilterChain original, List<Filter> filters) {
+            return new VirtualFilterChain(original, filters);
+        }
+
+    }
+
+    private static class VirtualFilterChain implements FilterChain {
+
+        private final FilterChain originalChain;
+        private final List<Filter> additionalFilters;
+        private final int size;
+
+        private int currentPosition = 0;
+
+        public VirtualFilterChain(FilterChain originalChain, List<Filter> additionalFilters) {
+            this.originalChain = originalChain;
+            this.additionalFilters = additionalFilters;
+            this.size = additionalFilters.size();
+        }
+
+        @Override
+        public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
+            if (this.currentPosition == this.size) {
+                this.originalChain.doFilter(request, response);
+                return;
+            }
+            this.currentPosition++;
+            Filter nextFilter = this.additionalFilters.get(this.currentPosition - 1);
+
+            nextFilter.doFilter(request, response, this);
+        }
+
+    }
+
+}

리뷰: > 궁금한점은 왜 VirtualFilterChain 에 FilterChainDecorator를 입혀 spring security에서는 사용하고 있는지 입니다.

VirtualFilterChain의 역할과 FilterChainDecorator의 역할의 역할이 달라서 그런데요.
VirtualFilterChain는 특정 조건을 기반으로 필터들을 실행하는 역할을 하고, FilterChainDecorator는 기존 FilterChain에 추가적인 로직을 삽입하거나 수정할 수 있도록 도와주는 역할을 합니다.

예시를 들어보자면 /a 요청과 /b 요청에 다른 보안 필터를 적용한다고 생각했을 때 `VirtualFilterChain`가 각 필터를 실행하는 역할을 담당하게 되고,
이미 구현된 필터를 감싸서 가능을 확장할 때 사용하는 것이 `FilterChainDecorator`의 역할이 됩니다.
즉 필터 체인을 동적으로 조작한다는 점에선 동일하지만, 목적과 사용 방식이 다를 것 같아요 ㅎㅎ