Spring/Debugging Spring

[스프링 디버깅 해보기] 스프링의 기본 오류 페이지 Whitelabel Error Page는 어떻게 생성될까?

2023. 4. 8. 05:18
목차
  1. ✅ 테스트 환경 세팅
  2. ✅ Springframwork 디버깅 과정
  3. 후기

진행하고 있는 무백스 스터디 이슈에서 스터디원분의 질문으로 인해 디버깅을 스프링의 기본 오류 페이지에 대한 생성과정을 직접 디버깅하여 정리해봤습니다.

아래 글 내용은 https://github.com/Invincible-Backend-Study/toby-spring-boot/issues/6 이슈에서도 볼 수 있습니다!

혹시라도 잘못된 내용이 있거나, 수정해야 하는 부분이 있다면 댓글로 알려주시면 감사하겠습니다!!!

 

✅ 테스트 환경 세팅

테스트용 Controller
존재하지 않는 viewName을 반환한다.

image



✅ Springframwork 디버깅 과정

DispatcherServlet은 가장먼저 “/”로 들어온 요청에 대해 처리를 시작합니다. 이때 요청 URI는 “/”가 되고, DispatcherType은 “REQUEST”가 됩니다.

image



TestController의 test()메소드가 해당 URI와 매핑되어있으므로 해당 컨트롤러를 실행하고 반환값으로 “dd”라는 viewName을 받게 됩니다.
해당 정보를 가지고 ModelAndView를 생성하고 내부 View 정보를 통해 RequestDispatcher가 forwarding 작업을 합니다.

image



포워딩 됐으므로 dispatcherType은 FORWARD이며, “/dd” 라는 리소스를 DispatcherServlet이 내부적으로 호출하게 됩니다.
다시 DispatcherServlet을 통해 내부적인 doService() → doDispatch 작업을 수행하게 됩니다.

image



DispatcherServlet.doDispatch()에서 HandlerAdapter를 찾아 handle()하게 되는데 이는 어댑터(HttpRequestHandlerAdapter)를 통해 찾아온 핸들러를 실행시키게 됩니다.

image

 

image



이때 정적 리소스를 처리하는 ResourceHttpRequestHandler가 선택되고 “/dd”에 대한 실제 리소스를 가져오지만 존재하지 않으므로 null값이 반환됩니다.
resource가 null이므로 Not Found 에러를 Response 객체에 세팅합니다. 이때 sendError내부 코드에서 setError를 통해 0 → 1로 에러 플래그를 세팅합니다.

image

 

image

 

image



사용자의 “/” 요청이 마무리되고 WAS까지 404 Error가 전파됩니다. 그리고 Tomcat에서 에러가 존재하는지 묻게 됩니다.
이때 아까 setError를 통해 1로 세팅한 에러값을 통해 에러가 있음을 WAS가 인지하게 됩니다.

image



이후 404 Not Found에 대한 에러 페이지를 찾게 됩니다. 따로 생성한 에러페이지는 존재하지 않으므로 WAS에서 생성하는 디폴트 에러 페이지를 찾게 됩니다.

image



/error 로케이션을 받아오고 이후 각종 에러에 대한 세팅을 해줍니다(DispatcherType을 ERROR 세팅 등)
이후 /error에 대해 WAS 내부에서 포워딩 작업을 실행합니다.

image

 

image



포워딩 작업이 시작됐으므로 다시 필터를 거치고 DispatcherServlet을 호출하게 됩니다.

image



“/error”로 requestURI가 선택되어 있는데 해당 uri는 BasicErrorController의 @RequestMapping과 일치합니다.

또한 Accept header가 text/html이므로 BasicErrorController#errorHtml 핸들러 메소드가 선택됩니다.
RequestMappingHandlerAdapter는 이런 @RequestMapping이 되어있는 핸들러를 지원하므로(HandlerAdapter#supports를 지원함) 어댑터로 선택됩니다.

image

 

image

 

image


(이 이미지는 좌측 하단의 main 쓰레드내 메소드 스택을 통해 흐름을 이해하기 편하도록 첨부했습니다.)



이후 실제 BasicErrorController#errorHtml을 실행합니다.

image



errorHtml의 내부 호출 메소드인 resolveErrorView에서는DefaultErrorViewResolver#resolveErrorView를 호출해 에러페이지에 대한 view resolving 수행합니다.

image



DefaultErrorViewResolver#resoveErrorView 에서는 두번째 사진의 staticLocations과 같은 순서로 view를 찾습니다.
하지만 일치하는 View가 없으므로 null을 반환하게 됩니다. BasicErrrorController#errorHtml에서는 반환된 ModelAndView 객체가 null값이라면 “error”라는 viewName을 가진 ModelAndView 객체를 생성해 반환합니다.

image

 

image



반환된 ModelAndView 객체를 처리하가 위해 ModelAndView 응답 value를 처리하는 핸들러로 ModelAndViewMethodReturnValueHandler가 선택됩니다.
이곳에서 뷰 이름 세팅, 응답 코드 세팅 , 리다이렉트에 대한 처리 등을 수행합니다.

image



이후 BasicErrorController#errorHtml을 통해 생성된 ModelAndView 객체가 DispatcherServlet으로 반환됩니다.
받아온 ModelAndView 객체 내부의 View를 reolving하는데 이때 ContentNegotiatingViewReolver가 선택됩니다.

image



ContentNegotiatingViewResolver#resolveViewName 에서는 getCandiateViews()를 통해 후보가 될 수 있는 View를 선택하고 이후 getBestView()를 통해 최적의 View를 선택합니다.

후보군 View로는 ErrorMvcAutoConfiguration$StaticView와 정적 리소스를 처리하는 InternalResourceView 2개가 선택된다.

image



best view로는 ErrorMvcAutoConfiguration$StaticView가 더 높은 우선순위를 가지고 있고, text/html에 대해 ErrorMvcAutoConfiguration$StaticView가 처리할 수 있으므로 즉시 해당 뷰를 반환합니다.

image



이후 DispatcherServlet은 받아온 ErrorMvcAutoConfiguration$StaticView를 통해 뷰 렌더링을 진행합니다.
실제 StaticView의 render 메소드를 살펴보면 우리가 익히 볼 수 있는 Whitelabel Error Page를 볼 수 있습니다. 여기서 이전에 정해진 error 내용과 status code를 결합해 응답 HTML을 완성합니다.

image



응답 처리를 마치고 브라우저에는 404 Whitelabel Error Page가 응답됩니다.

image



후기

스프링 프레임워크의 코드를 디버깅해보면서 느낀것지만 상당히 양이 방대하며, 사소한 것들 하나하나 정말 많은 코드들이 존재합니다.
모든 코드에 대한 설명을 해석하고 적기에는 굉장히 양이 많고, 시간적 압박이 컸으므로.. (사실 이것만 해도 하루 종일 디버깅을 했습니다.. ㅎㅎ) 최대한 핵심이 되는 내용을 담으려고 노력했습니다.

 

이전 자바 웹 프로그래밍 Next Step 책 스터디를 통해 Spring MVC의 구조에 대해 꽤 알게 됐다고 생각하고 자신있게 디버깅을 시도했습니다만,
예상보다 방대한 양의 코드와 아직 부족한 디버깅 실력으로 코드를 이해하는데 꽤 많은 시간이 걸렸습니다.

 

그래도 이렇게 디버깅을 통해 실제 프레임워크를 분석해보면서 느낀건 어떤 코드를 보면 내부 구조를 반드시 전부 해석하고 이해해야했던 과거와 달리 직관적으로 해석할 수 있는 능력(메소드 이름, 클래스 명, 변수명 등을 통해)이 많이 향상된 것 같습니다!

저작자표시 (새창열림)
  1. ✅ 테스트 환경 세팅
  2. ✅ Springframwork 디버깅 과정
  3. 후기
'Spring/Debugging Spring' 카테고리의 다른 글
  • [Tomcat 디버깅 해보기] mapper.writeValue() 이후 response.setStatus()를 하면 안되는 이유
HiiWee
HiiWee
HiiWee
HiiWee's Devlog
HiiWee
전체
오늘
어제
  • 분류 전체보기 (42)
    • 우아한테크캠프 7기 (1)
    • 스터디 (30)
      • [도서] 자바 웹 프로그래밍 Next-Step (6)
      • [온라인] WhiteShip - Live Stud.. (11)
      • Spring Boot 스터디 (13)
    • Java (2)
    • Spring (6)
      • Debugging Spring (2)
      • [Toy] My-Little-Blog 기록 (4)
      • Spring Security (0)
    • DataBase (0)
    • Algorithm (0)
    • 도서 (0)
    • 일상 (2)

블로그 메뉴

  • 홈
  • 태그
  • 방명록
  • GitHub
  • 글쓰기

공지사항

인기 글

태그

  • 커스텀에러코드
  • 1일 1커밋
  • spring rest docs
  • JSCODE
  • 스터디
  • 회고
  • 토이프로젝트
  • elastic beanstalk
  • 무백스
  • Whitelabel Error Page
  • JSP
  • jwt
  • 라이브스터디
  • db
  • JPA
  • 우아한테크캠프 7기
  • MLB
  • api 문서
  • Github Actions
  • spring boot
  • JSON Web Token
  • objectmapper
  • 무중단 배포
  • 우아한테크캠프
  • Spring Framwork
  • Java
  • 테스트 코드 최적화
  • Spring
  • Servlet
  • Generic

최근 댓글

최근 글

hELLO · Designed By 정상우.
HiiWee
[스프링 디버깅 해보기] 스프링의 기본 오류 페이지 Whitelabel Error Page는 어떻게 생성될까?
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.