@RequestParam을 처리해주는 아규먼트 리졸버 = RequestParamMethodArgumentResolver
RequestParamMethodArgumentResolver는 AbstractNamedValueMethodArgumentResolver를 상속한 콘크리트 클래스고, resolveArgument를 오버라이딩 하지 않았기 때문에 AbstractNamedValueMethodArgumentResolver.resolveArgument가 호출된다.
흐름도
일단 흐름도는 이러하다.
어제 살펴봤던 내용은 DispatcherServlet
이전의 처리내용이었다.
스프링 MVC에 대해서 교환대라고 할 수 있는 DispatcherServlet
이 클래스가
HandlerAdapter 등..
조건에 부합하는 객체들을 찾아서 전달을 다 해준다.
@RequestParam
이 있을 때는 당연히 매핑이 되어서 가져올것은 알았지만
없을 때 생략해도 가져오는 이것은 동작이 어떻게 되는지 궁금했다.
코드부터 보자.
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello(String id, String name) {
return id + name;
}
@GetMapping("/hello2")
public String hello2(@RequestParam String id, String name) {
return id + name;
}
}
이러한 두개의 예시 hello, hello2를 만들었고 테스트 코드로 디버깅하는게 더 좋을것 같아서
테스트 코드로 디버깅을 진행했다.
@WebMvcTest(HelloController.class)
@AutoConfigureMockMvc
class HelloControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
void hello() throws Exception {
mockMvc.perform(get("/hello?id=lsj&name=홍길동"))
.andDo(print())
.andExpect(status().isOk());
}
}
일단 돌리게 되었을 때 DispatcherServlet
이 RequestMappingHandlerAdapter
를 호출하게 된다.
여기서 요청 객체를 처리하는줄 알았었는데
ArgumentResolver
들 중에 해당 객체를 처리할 수 있는 Resolver
클래스를 찾는다.
RequestMappingHandlerAdapter
의 일부 메소드인데 이 클래스가
부름을 받으면 바로 Resolver
들을 추가해주는데
여기서 유심히 봐야하는 부분이 디버그로 파란줄 쳐진 부분과
//catch-all
아래 2번째줄 이 두줄을 유심히 봐야하는데
여기서 내가 느낀것은 useDefaultResolution
이 옵션이라고 생각하고 넘어갔다.
HandlerMethodArgumentResolverComposite
다음은 저 어댑터들을 가지고서 넘어온 파라미터를 처리해줄 수 있는 Resolver
들을 찾는데
그것은 이 HandlerMethodArgumentResolverComposite
에서 for문으로 찾아주게 되어있다 ❗️❗️❗️❗️
RequestParamMethodArgumentResolver
여기서 체크하는 로직이 위 이미지 RequestParamMethodArgumentResolver
이다.
보면 파라미터 어노테이션을 갖고 있는지 여부, 또는 @RequestPart
를 갖고있는지 등등
분기로 판단해서 객체를 처리하려고 한다.
여기서 아까 보고 넘어갔다했던 useDefaultResolution
애가 분기문에 this.useDefaultResolution
이 보이는데
이게 true라면 현재 가지고있는 매개변수의 타입대로 따라가서 값을 매핑시켜준다.
0번째 인자는 false
, 25번째 인자는 true
를 갖고있다.
정리를 해보자면
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
상태값이 false
이면 @RequestParam
이 있는 경우 매개변수 생성
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
상태값이 true
이면 @RequestParam
이 없는 경우 매개변수 생성을 하는 것
그래서 둘다 있으나 없으나 생성을 해준다.
근데 이제는 성능은 어떤게 좋냐고 묻는다면 명시적으로 @RequestParam
을 붙인 객체는 0번째에서 바로
찾아서 매핑이 될것이다.
반대로 명시적으로 붙이지 않았다면?
매번 25번째에 있는 Resolver
를 통해서 매핑시키게 될 것이다. 이게 단순 한개라면 모르겠지만,
여러 사용자 + 여러 스레드 + 파라미터의 갯수
세개의 조건이 셋중에 하나 또는 전부가 많아진다면
성능은 안좋아질게 훤히 보인다.
그래서 안붙여도 되지만 성능을 최적화 하려면 명시적으로 @RequestParam
을 붙여주는것이 좋다.
정리
테코톡에서 디버그를 본 후에 깊게 한번 들어와서 공부를 해보려고 어제부터 탐색을 했다.
깊게 이렇게 들어와서 하나씩 보는것이 소스분석에도 도움이 되고 더 나아가서는
회사코드를 인계받을 때에도 이렇게 분석을 하면 핵심 로직을 빠르게 파악할 수 있을 것 같다.
그러면서 동시에 이렇게 정리까지 하니 머릿속에 많이 남아서 지식으로 가져가는 것도 좋은것 같다.
공부를 이렇게 했어야 됐는데 너무 늦은건가 싶기도 하지만 꾸준한게 답인것 같다. 🔥🔥🔥
'디버깅' 카테고리의 다른 글
AWS SNS 토큰 에러 (0) | 2022.08.10 |
---|---|
YAML 파일을 읽어보자 (0) | 2022.08.09 |
AbstractMessageConverter (0) | 2022.08.09 |
RequestMapping 동작 (0) | 2022.08.09 |