HandlerMethodArgumentResolver 동작
호돌맨 님의 강의에서 JWT 토큰을 통한 인증 로직을 사용하기 위해서 HandlerMethodArgymentResolver를 사용하였다.
이를 통해서 컨트롤러에 접근 하기 이전 인증 허가를 처리하는 방법을 사용했는데 정확하게 어떤 시점에 사용되는지 등 자세한 내용을 정리해보자 한다.
1. HandlerMethodArgumentResolver 란❔
정의는 컨트롤러 메서드에서 특정 조건에 맞는 파라미터가 있을 때 원하는 값을 바인딩 하는 인터페이스이다.
이를 이해하기 위해서 Spring MVC의 아키텍처를 가볍게 보고 넘어가보자
Dispatcher 서블릿에서 요청된 모든 리퀘스트를 가장 처음 받아준다.(프론트 컨트롤러 역할)
그리고 이 서블릿에서 핸들러 조회를 하고 핸들러 처리 가능 핸들러 어뎁터를 찾고 이 핸들러(컨트롤러)를 호출한다.
HandlerMethodArgumentResolver는 4번 동작의 사이에서 호출된다.
이름 그래도 핸들러 메소드의 인자값을 분석하는 기능을 수행하기 때문에 처리할 핸들러를 찾고 그 핸들러를 실행하기 전에 동작되는 것이다.
4번 단계를 ArgumentResolver를 포함해서 한번 확인해보자
핸들러 어텝터는 바로 컨트롤러로 가지 않고 아래의 순서를 따른다.
✅ 동작 순서
1. 컨트롤러에 요청/응답 처리 전 핸들러 어댑터는 ArgumentResovler에 요청
2. ArgumentResolver 는 Controller 를 보고 파라미터 찾음
3. 핸들러는 어댑터에게 파라미터 반환
4. 핸들러 어댑터는 파라미터 가지고 컨트롤러 처리
5. 컨트롤러를 처리하고 결과 값을 HandlerMethodReturnValueHandler 인터페이스를 처리
HandlerMethodReturnValueHandler 는 @ResponseBody, String, ModelAndView 등의 처리를 위해서 이용
우리가 사용하는 RequestParam, ModelAtrribute 와 같은 리퀘스트 인자값에 사용하는 어노테이션을 처리를 HandlerArgumentResolver의 구현체들이 처리한다.
HandlerMethodReturnValueHandler 주요 메서드는 2가지로 구성된다.
👉 supportsParameter
주어진 컨트롤러(핸들러)의 매개변수가 어떤 어노테이션이 붙어 있는지 확인하고, 이 매개변수의 처리 여부를 반환 해준다.
👉 resolveArgument
HTTP 의 요청 본문을 읽어서 어노테이션이 붙은 배개 변수에 대한 실제 객체를 생성한다.
자세한 사항은 아래 예시에서 함께 설명하겠다.
✔ 구현체 마다 실제로 수행하는 역할이 다르다
2. 예시 설명
우리는 Login 이라는 어떤 Request 클래스, 로그인을 처리하는 컨트롤러 2가지 있다고 가정한다.
public class Login {
private String username;
private String password;
}
@PostMapping("/login")
public String login(@RequestBody Login login) {
// 로그인 처리 로직
return "redirect:/home";
}
✅ 동작 과정
1️⃣ 요청 수신
클라이언트가 /login 이 포함된 JSON 형태의 로그인 정보가 포함되어 있다.
{
"username": "user",
"password": "password"
}
2️⃣ 핸들러 맵핑 & 어댑터 호출
/login 엔트포인트에 대한 컨트롤러 메서드를 찾고, HandlerAdapter 가 컨트롤러 메서드를 실행하기 위해서 호출한다.
3️⃣ 매개변수 준비
HandlerAdapter 는 메서드의 매개변수를 준비하기 위해 여러 HandlerMethodArgumentResolver를 순차적으로 실행한다.
HandlerMethodArgumentResolver를 구현한 모든 구현체들을 확인하면서 이 매개변수를 처리할 수 있는 구현체를 찾는다.
이때 이를 supportsParameter 메서드를 통해서 구현체가 매개변수를 처리할 수 있는지 확인한다
4️⃣ 매개변수 생성
전체를 순회한 이후 resolveArgument를통해서 매개변수를 실제 클래스로 만들어서 반환해준다.
어떤 오브젝트인지 정의하기는 어렵기 때문에 오버라이드 함수의 반환 타입은 Object 이다.
5️⃣컨트롤러 메서드 호출
이렇게 준비된 Login 객체로 HandlerAdapter에서 컨트롤러의 메서드인 login(@RequestBody Login login)의 호출한다.
6️⃣응답 처리
컨트롤러에서 처리된 응답을 다시 어댑터, 프론트컨트롤러로 넘겨 뷰 또는 프론트 서버로 전달한다.
이 예제에서는 @ResponseBody를 사용해서 RequestResponseBodyMethodProcessor 라는 Spring 에서 구현체로 제공하는 리졸버를 사용하지만 사용자만의 커스텀 리졸버 구현체를 만들어서 사용도 가능하다.
3. CustomResolver 등록
앞서 설명 한 것처럼 기존의 Resolver이후에 자신이 원하는 특정한 클래스의 요청 타입을 처리하게 하는 방법도 가능하다.
@Component
public class CustomHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter methodParameter) {
return methodParameter.getParameterType().equals(Custom.class);
}
@Override
public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
Custom custom = new Custom();
....
return custom;
}
}
먼저 커스텀 HandlerMethodArgumentResolver 구현체를 만든다.
그리고 이 구현체를 사용한다는 것은 Spring MVC 의 Configuration에 등록해줘야한다.
@Configuration
@RequiredArgsConstructor
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new CustomHandlerMethodArgumentResolver));
}
}
이런식으로 사용하면 된다.
단순하게 매개변수 처리 뿐만 아니라 특정 매개 변수를 처리할 때 조건을 걸어서 인증 기능을 수행할 수 도 있다.
4. 정리
이번 포스팅에서는 HandlerMethodArgumentResolver 의 동작 방식에 대해서 알아 보았다.
실제 구현체는 정말 많이 있으며 모든 구현체에 대한 설명을 진행 할 수 없지만 필요한 상황에 따라 추가적으로 학습 해주면 좋을 곳 같다.
추후 인터셉트에 대한 포스팅 이후 인터셉트와 핸들러 메소드 리졸버의 차이점을 추가로 알아보자
'Spring' 카테고리의 다른 글
[Spring 시큐리티] 사용자 인증 (0) | 2024.06.26 |
---|---|
Spring Interceptor 동작 방식 (1) | 2024.06.10 |
[Spring Petclinic]1. application properties (0) | 2024.04.27 |
Spring MVC - frontController (0) | 2024.03.14 |
Spring MVC 패턴 - Servlet (0) | 2024.03.06 |