반응형

🎯 0. 역직렬화 & 직렬화란?

이론적인 직렬화, 역직렬화는 다음과 같다.

 

* 직렬화 : 메모리를 디스크에 저장하거나, 네트워크 통신에 사용하기 위한 형식으로 변환하는 것

 

* 역직렬화 : 디스크에 저장한 데이터를 읽거나, 네트워크 통신으로 받은 데이터를 메모리에 쓸 수 있도록 변환하는 것

 

 

일반적으로 스프링 HTTP 요청 / 응답 과정에서의 직렬화, 역직렬화를 생각해보면 다음과 같다.

 

* 직렬화 : 자바 객체를 Byte, CSV, JSON, XML 등 네트워크 통신을 위한 다양한 포맷으로 변환하는 것!

                주로 자바 객체 -> JSON을 사용한다.

 

* 역직렬화 : 네트워크 통신으로 받은 Byte, CSV, JSON, XML 등 다양한 포맷을 자바 객체로 변환하는 것!

                주로 JSON -> 자바 객체를 사용한다.

 

 

요약하면, 자바 객체 ↔ JSON 간에 변환을 하는 것이 직렬화 & 역직렬화이다.

 

HTTP 응답은 서버 → 클라이언트 흐름이기 때문에 자바 객체 → JSON 변환인 직렬화 과정이고,

HTTP 요청은 클라이언트 → 서버 흐름이기 때문에 JSON 요청 → 자바 객체 변환인 역직렬화 과정이다.

 

쉽게 설명하면,

ResponseDto를 HTTP 응답에 담을 때 ResponseDto를 JSON으로 변환하는 과정이 직렬화 과정이고

JSON HTTP 요청 시 JSON이 RequestDto로 변환되는 과정이 역직렬화 과정이다.

 

역직렬화 & 직렬화의 개념도 알아봤으니

이제, 스프링이 HTTP 요청 & 응답 시 어떻게 역직렬화 & 직렬화를 하는지 살펴보자.


🎯 1. 역직렬화 & 직렬화 전체 흐름 

 

✅ 1-1. HTTP 요청 역직렬화 흐름


      
1. HTTP API 요청
2. 요청에 맞는 `HttpMessageConverter` 사용
3. `HttpMessageConverter`에서 `ObjectMapper`를 사용해서
데이터(XML, JSON 등) -> 자바 객체로 역직렬화한 결과 반환

 

✅ 1-2. HTTP 응답 직렬화 흐름


      
1. 보낼 응답에 맞는 `HttpMessageConverter` 사용
2. `HttpMessageConverter`에서 `ObjectMapper`를 사용해서
자바 객체 -> 데이터(XML, JSON 등)로 직렬화한 결과를 반환

 

💡 HTTP 요청, 응답 흐름 요약

HTTP 요청과 응답 흐름을 공통적으로 요약해보면 다음과 같다.


      
1. 적절한 `HttpMessageConverter` 탐색
2. 찾은 `HttpMessageConverter`에서 역직렬화 & 직렬화한 결과 반환

 

공통적으로 등장하는 `HttpMessageConverter` 녀석이 역직렬화 & 직렬화 책임을 수행하는 객체이다!

 

요약한 HTTP 요청, 응답 흐름대로 `HttpMessageConverter`를 살펴보자!!


🎯 2. 적절한 `HttpMessageConverter 탐색`

 


      
* HTTP 요청 : @RequestBody, RequestEntity 객체
* HTTP 응답 : @ResponseBody, ResponseEntity 객체

위와 같은 어노테이션, 객체가 있으면 HttpMessageConverter를 호출해서 변환을 거친다.

 

※ HTTP 요청 & 응답 시 HttpMessageConverter 리스트

해당 리스트에 있는 Converter 중에서 적절한 Converter를 가져와서 사용한다.

그렇다면, 적절한 Converter를 어떻게 판단할까?

 

 

✅ HttpMessageConverter 인터페이스


      
package org.springframework.http.converter;
public interface HttpMessageConverter<T> {
boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);
boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType);
List<MediaType> getSupportedMediaTypes();
T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException;
void write(T t, @Nullable MediaType contentType, HttpOutputMessage
outputMessage)
throws IOException, HttpMessageNotWritableException;
}

💡 canRead() & canWrite()

👉 HttpMessageConverter가 해당 클래스, 미디어 타입을 지원하는지 체크

 

HttpMessageConverter의 해당 메소드를 사용하여, 적절한 Converter를 찾아서 사용하게 된다.

 

적절한 Converter를 찾는 과정을 살펴보자.

 

✅ 2-1. HTTP 요청 시 적절한 HttpMessageConverter 탐색 과정


      
1. HTTP 요청 들어옴
2. Controller에서 @RequestBody, RequestEntity를 파라미터에서 사용하면
HttpMessageConverter 리스트 탐색
3. 해당 데이터를 읽을 수 있는지 판단하기 위해 HttpMessageConverter 리스트를 돌면서
해당 Converter의 `canRead()` 메소드 호출
3-1. HTTP 요청으로 온 해당 클래스 타입을 지원하는가?
(ex : String[], 객체, ...)
3-2. HTTP 요청으로 온 미디어 타입(Content-Type)을 지원하는가?
(ex : `text/plain`, `application/json`)
4. 3-1, 3-2의 조건을 만족하면 `canRead()`가 true를 반환

 

 

✅ 2-2. HTTP 응답 시 적절한 HttpMessageConverter 탐색 과정


      
1. Controller에서 @ResponseBody, ResponseEntity를 파라미터에서 사용하면
HttpMessageConverter 리스트 탐색
2. 해당 데이터를 읽을 수 있는지 판단하기 위해 HttpMessageConverter 리스트를 돌면서
해당 Converter의 `canWrite()` 메소드 호출
2-1. HTTP 응답으로 보낼 해당 클래스 타입을 지원하는가?
(ex : String[], 객체, ...)
2-2. HTTP 응답으로 보낼 Accept 미디어 타입(Content-Type)을 지원하는가?
(ex : `text/plain`, `application/json`)
3. 2-1, 2-2의 조건을 만족하면 `canRead()`가 true를 반환

🎯 3. 찾은 HttpMessageConverter에서 역직렬화/직렬화한 결과 반환

 

2번 과정을 거쳐서, 적절한 HttpMessageConverter를 찾았다.

그렇다면, 찾은 HttpMessageConverter에서 역직렬화 & 직렬화의 결과를 어떻게 생성할까?

 

다시 HttpMessageConverter 인터페이스를 살펴보자.

 

✅ HttpMessageConverter 인터페이스


      
package org.springframework.http.converter;
public interface HttpMessageConverter<T> {
boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);
boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType);
List<MediaType> getSupportedMediaTypes();
T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException;
void write(T t, @Nullable MediaType contentType, HttpOutputMessage
outputMessage)
throws IOException, HttpMessageNotWritableException;
}

💡 read() & write()

👉 HttpMessageConverter를 통해 요청 & 응답 메시지를 읽고 쓰는 기능 수행

 

HttpMessageConverter의 해당 메소드를 사용하여, 역직렬화 & 직렬화 결과를 생성한다.

 

이때, ObjectMapper 클래스를 사용하여 역직렬화 & 직렬화 결과를 생성한다.

 

ObjectMapper는 ObjectReader, ObjectWriter를 생성하는 팩토리 역할을 수행한다.

(그 이상의 자세한 원리는 너무 깊은 것 같아서 다루지 않았다.)

 

 

✅ 3-1. HTTP 요청 : 역직렬화 -> ObjectReader.readValue()로 자바 객체 생성


      
...
objectReader.readValue(inputStream);

 

※ HttpMessageConverter의 read() 메소드

 

`objectReader.readValue()`를 통해 요청으로 들어온 데이터가 자바 객체로 역직렬화되어 반환된다.

 

 

 

✅ 3-2. HTTP 응답 : 직렬화 -> ObjectWriter.writeValue()로 데이터 생성


      
...
objectWriter.writeValue(generator, value);

`objectWriter.writeValue()`를 통해 응답으로 나갈 데이터가 XML, JSON 등으로 직렬화되어 반환된다.


🎯 4. 스프링 HTTP API 요청 & 응답 시 역직렬화 직렬화 원리 요약


      
* @RequestBody, @ResponseBody, RequestEntity, ResponseEntity가 존재할 때
1. 메시지 컨버터 리스트를 돌면서 적절한 `HttpMessageConverter` 탐색
2. 찾은 `HttpMessageConverter`에서 ObjectMapper로 역직렬화 & 직렬화한 결과 반환

 

반응형
BE_성하