시작하기 전 하나만 말씀드리겠습니다.
내용 자체도 어렵고, 제가 공부할 목적으로 쓴 글이다 보니, 난잡하고 옳지 않은 내용이 존재할 수 있습니다. 수정할 부분을 알려주시면 바로 수정 하겠습니다 😁
웹서버와 WAS
Spring Ioc Container (= Spring Container)
본격적으로 하나하나 뜯어보기전, 전체적인 흐름도부터 잡고 들어가자.
밑 사진은 이후 설명에서 자주 언급할 것이므로, 상세하게 보거나 옆에 다른창으로 아에 올려놔도 좋을것 같다

전체적인 진행 과정은 다음과 같다.
- Client 요청 수신
- Web Server에서 정적 리소스 처리 및 동적 처리를 위해 WAS로 요청 전달
- FilterChain 통과하며 로깅, 보안, 전처리, 파싱등을 처리
- DispatcherServlet에서 요청에 알맞는 핸들러 매핑
- Controller에서 해당 비지니스 로직(Service)로 연결
- Service 처리에 DB가 처리하다면 Repository로 이동후 DB와 통신
- 결과는 HttpResponse로 변환되어 Client에게 반환
그럼 과정별 나온 개념들을 하나하나 뜯어보기 시작하자
web server에서 동적요청을 WAS에 보내면, 제일 먼저 도착하는 곳이 Filter Chain이다.
Filter 는 이름 그대로 무언갈 걸러내는 역할을 담당한다.
그 Filter를 모아놓아 순서대로 연결해 놓은 것이 Filter Chain이다.

위 그림에서 Servlet은 맨 위 그림에 나와있던 Dispatcher Servlet이며, 이에 대한 자세한 내용은 후술하겠다.
위 그림처럼, Client에게 요청을 받거나 응답을 거칠때에는 FilterChain에 들어있는 Filter들을 하나하나 거치며 전/후처리 작업이나 파싱, 보안 작업등을 진행한다.

맨 위에서 봤던 사진을 다시 한번 보자.

자세히 보면 FilterChain은 Spring Container가 아닌 ServletContainer의 소속인것을 알 수 있다
이 말은 즉, Spring Container에서 자동으로 지원해주던 IoC 기능, 즉 Bean을 삽입해주거나 Filter를 Bean으로 등록하는 기능이 사용 불가능하다는 뜻이다.
그 이외에도 Spring Continer가 지원해주는 모든 기능들이 사용이 불가능하다.
하지만, SpringBoot를 개발하다보면 Filter를 Bean으로 등록해 사용해야 하는 상황이 온다.
@RequiredArgsConstructor
public class FilterConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
private final JwtTokenProvider jwtTokenProvider;
private final ObjectMapper objectMapper;
@Override
public void configure(HttpSecurity http) {
JwtFilter jwtTokenFilter = new JwtFilter(jwtTokenProvider);
GlobalExceptionFilter globalExceptionFilter = new GlobalExceptionFilter(objectMapper);
http.addFilterBefore(jwtTokenFilter, UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(globalExceptionFilter, JwtFilter.class);
}
}
위 코드는 Config 파일에 Filter를 등록하는 모습이다.
결론적으로는, Filter 클래스를 다른 클래스에서 사용을 해야한다는건데..
이러면 또 new로 인스턴스를 생성하는건 둘째 치고, Filter Config에 의존성이 변경될때마다 Filter Config를 사용하는 모든 설정 파일을 건들여아 한다.
상상만 해도 진짜 끔찍하다;;
이런걸 해결하기 위해 등장한것이 바로 DelegatingFilterProxy다.

DelegatingFilterProxy는 springSecurityFilterChain이름으로 생성된 Bean을 Application Context에서 찾아서 위임하는 역할을 한다.
이렇게 말하면 이해가 안될텐데, 그림자료를 한번 보자.

결론적으로는 DelegatingFilterProxy는 SpringSecurityFilterChain으로 요청을 넘긴다. 그런데 SpringSecurityFillterChain은 Spring IoC Container 안에 위치해 있기때문에 Bean의 사용이 가능해진다.
그래서 보통, 사용자 정의 필터를 정의할때 SecurityFilterChain에 포함시키는 것이다.
그런데 제일 큰 문제중 하나가, DelegatingFilterProxy는 기본적으로 ApplicationFilterChain(서블릿 컨테이너가 관리하는 필터 체인)이며, 직접적으로 Bean을 사용하는 SpringSecurityFillterChain에 접근할 수 없다.
때문에, 내부적으로 위임대상이 있다. 해당 위임대상은 Spring IoC Container안에 위치하며, SecurityFilterChain의 직접적인 제어, 요청전달을 담당한다. 해당 필터가 바로 FilterChainProxy이다.

FilterChainProxy는 DelegatingFilterProxy에 포함되어 있으며, Security FilterChain에 직접적으로 연결하여 요청을 넘기는 역할을 담당합니다.
DelegatingFilterProxy는 FilterChainProxy에 요청을 위임하며, FilterChainProxy는 각 요청에 대하여 직접적으로 연결된 필터들을 호출하면서 작동합니다.
이제 요청을 필요한 곳에 보내주는 DispatcherServlet에 대해 알아보자.
DispatcherServlet은 기본적으로 FrontController로, HTTP가 보내는 모든 요청을 수신, 가장 먼저 받아서 필요한 컨트롤러로 할당해주는 역할을 담당한다.
FrontController: 서블릿 컨테이너에서 모든 요청이 거치게 되는 곳으로, 모든 요청들을 처리해주는 컨트롤러를 뜻한다.
즉, 기본적으로 요청이 수신되면, FilterChain을 거친 후 DispatcherServlet가 가로채며, 분석후, 필요한 세부 컨트롤러로 보내주는 역할을 담당한다.
즉, 우리가 User 컨트롤러와 Post 컨트롤러를 만들어 놓으면, DispatcherServlet이 어디에 필요한 요청인지 분석한 후 해당 컨트롤러에 요청을 위임해준다.

- 클라이언트가 요청 URI와 함께 정보를 요청한다.
- 요청한 URI에 맞는 Controller를 찾아 HandlerMapping에 전달
- HandlerMapping이 Conroller에 요청을 위임함
- Controller에서 처리(Service, Repository 작업 포함) 후 DispatcherServlet에게 전달
(이후 View와 View Resolver같은 경우 Stateless하고 Back-End만 다룰 서버의 경우 불필요함으로 생략)
본래, Servlet같은 경우는 들어온 요청이 Web.xml을 거치며 해당 컨트롤러를 직접 찾았어야 했다.

하지만, DispatcherServlet이라는 중앙 집중적 컨트롤러가 등장하며, DispatcherServlet이 모든 요청을 핸들링 해주는 HandlerMapping을 사용하여 효율을 증대시켰다.
일단 이 개념을 이해하기 위해서는 ApplicationContext의 개념에 대하여 알아야 한다. ApplicationContext는 쉽게 스프링이 관리하는 Bean들이 담겨있는 컨테이너라고 생각하면 된다.
즉, ApplicationContext는 Spring Container의 한 종류라고 볼 수 있는 것이다. 다만, ApplicationContext는 Bean Factory + 부가기능으로 이루어져 있으며, Bean Factory를 직접적으로 사용하기 보다는 ApplicationContext를 사용하는 경우가 더 많다. 왜냐하면 ApplicationContext가 Bean Factory의 기능을 거의 모두 가지고 있기 때문이다.
BeanFactory
SpringBoot의 최상위 인터페이스로, 빈을 관리, 조회하는 역할을 담당한다.
이 ApplicationContext는 기본적으로 Interface로 정의되어 있다.

때문에 ApplicationContext를 구현해줄 클래스가 필요하다. 바로 그 클래스가 Root WebApplicationContext이다.
Root WebApplicationContext는 당연히 스프링 컨테이너 안에 위치한다.
그런데 ApplicationContext의 또다른 구현체가 존재한다. 바로 WebApplicationContext이다. 이 구현체는 DispacherServlet의 동작을 돕기 위해 존재하는 컨테이너로, DispacherServlet이 사용하는 Controller같은 빈들을 저장하는데에 사용한다.
기본적으로 WebApplicationContext은 Root WebApplicationContext을 기반으로 제작된다. 즉, 부모-자식 관계로 제작된다는 것이다.
따라서 WebApplicationContext는 Root WebApplicationContext의 데이터에 접근이 가능하다. (반대는 불가능하다)




마지막으로, 처음 봤던 사진을 다시보자

흐름을 중점으로 각각의 기능들을 떠올리면서 복습해보자.
긴 글 읽느라 고생하셨습니다. 오늘 하루도 배움이 많은 하루가 되시길 바라겠습니다!
Tomcat Filter와 Spring Interceptor
Spring Security 개요
Spring 공식문서 - Spring Security의 구조
[스프링 시큐리티] 필터(DelegatingFilterProxy, FilterChainProxy)
[Spring Security] DelegatingFilterProxy의 동작과정
Spring Security - 1. DelegatingFilterProxy 알아보기
Spring Web MVC의 Dispatcher Servlet의 동작 원리
Servlet (서블릿이란? 그리고, Dispatcher Servlet이란 ?)
WebAplicationContext 란?
[Spring] 스프링 컨테이너(ApplicationContext)
[Spring] ContextLoaderListener 란? RootApplicationContext과 WebApplicationContext란?