데이터 바인딩 흐름

tokkaiiii·2025년 5월 1일

spring-mvc

목록 보기
14/27
//DispatcherServlet에서 요청을 받음
 HttpServletRequest processedRequest = request;
 // HandlerAdapter 에서 handle 실행
  mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// RequestMappingHandlerAdapter 가 받음
// handlerInternal 메소드에서 핸들러메소드를 invoke 함
mav = this.invokeHandlerMethod(request, response, handlerMethod);
// binderFactory 만듬
 WebDataBinderFactory binderFactory = this.getDataBinderFactory(handlerMethod);
 // 따라가보면 만들고 있는데 여기 메소드도 들어가보면
 DefaultDataBinderFactory factory = this.createDataBinderFactory(initBinderMethods);
 // ServletRequestDataBinderFactory를 만들고 있다
protected InitBinderDataBinderFactory createDataBinderFactory(List<InvocableHandlerMethod> binderMethods) throws Exception {
    return new ServletRequestDataBinderFactory(binderMethods, this.getWebBindingInitializer());
  }
// 이렇게 만들어진 binderFactory를 invocableMethod 안에 저장
 invocableMethod.setDataBinderFactory(binderFactory);
// 그 다음 invokeAndHandle 실행
invocableMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);

invokeAndHandle 에 들어가면 invokeForRequest를 실행한다

 Object returnValue = this.invokeForRequest(webRequest, mavContainer, providedArgs);
// 여기서 아큐먼트 값을 구하고 리턴 받는다
Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);

//getMethodArgumentValues 이 메소드 상세하게 보면
@Nullable
  public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
    HandlerMethodArgumentResolver resolver = this.getArgumentResolver(parameter);
    if (resolver == null) {
      throw new IllegalArgumentException("Unsupported parameter type [" + parameter.getParameterType().getName() + "]. supportsParameter should be called first.");
    } else {
      return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
    }
  }
//  여기서 resolver를 받고 지금은 ServletModelAttributeMethodProcessor 라는 아큐먼트리졸버 구현체다

ModelAttributeMethodProcessor 의 resolveArgument 자세히 보자

resolveArgument
// 이름을 가져옴
 String name = ModelFactory.getNameForParameter(parameter);
 // 변수를 선언했는데 여기에 컨트롤러의 매개변수의 객체를 담아서 반환할 것이다
Object attribute;
// (1) 세션에 이미 저장된 것이 있으면 가져오는 로직
if (mavContainer.containsAttribute(name)) {
      attribute = mavContainer.getModel().get(name);
      if (attribute == null || ObjectUtils.unwrapOptional(attribute) == null) {
        bindingResult = binderFactory.createBinder(webRequest, (Object)null, name).getBindingResult();
        attribute = wrapAsOptionalIfNecessary(parameter, (Object)null);
      }
    }
// (2) 컨버터를 통해 만드는 과정
 attribute = this.createAttribute(name, parameter, binderFactory, webRequest);
  if (bindingResult == null) 
  // 여기서 factory가 binder 객체 생성
   WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name, type);
// attribute 가 null 이면 생성자에서 생성할 것인지 본다
if (attribute == null) {
        this.constructAttribute(binder, webRequest);
        attribute = wrapAsOptionalIfNecessary(parameter, binder.getTarget());
      }
// 여기서 createObject해서 결과가 target에 담긴다
 public void construct(ValueResolver valueResolver) {
    Assert.state(this.target == null, "Target instance already available");
    Assert.state(this.targetType != null, "Target type not set");
    this.target = this.createObject(this.targetType, "", valueResolver);
    if (!this.getBindingResult().hasErrors()) {
      this.bindingResult = null;
      if (this.typeConverter != null) {
        this.typeConverter.registerCustomEditors(this.getPropertyAccessor());
      }
    }

  }
  // 리플렉션 기술을 통해서 값을 담는다
   result = BeanUtils.instantiateClass(ctor, args);

setter 로 바인딩하는 것을 보자

 protected void bindRequestParameters(WebDataBinder binder, NativeWebRequest request) {
    ((WebRequestDataBinder)binder).bind(request);
  }

 public void bind(WebRequest request) {
    if (!this.shouldNotBindPropertyValues()) {
      MutablePropertyValues mpvs = new MutablePropertyValues(request.getParameterMap());
      if (request instanceof NativeWebRequest) {
        NativeWebRequest nativeRequest = (NativeWebRequest)request;
        MultipartRequest multipartRequest = (MultipartRequest)nativeRequest.getNativeRequest(MultipartRequest.class);
        if (multipartRequest != null) {
          this.bindMultipart(multipartRequest.getMultiFileMap(), mpvs);
        } else if (StringUtils.startsWithIgnoreCase(request.getHeader("Content-Type"), "multipart/form-data")) {
          HttpServletRequest servletRequest = (HttpServletRequest)nativeRequest.getNativeRequest(HttpServletRequest.class);
          if (servletRequest != null && HttpMethod.POST.matches(servletRequest.getMethod())) {
            StandardServletPartUtils.bindParts(servletRequest, mpvs, this.isBindEmptyMultipartFiles());
          }
        }
      }

      this.doBind(mpvs);
    }
  }
profile
풀스택 자바 개발자입니다

0개의 댓글