JAVA
Java의 직렬화(Serialize)
wellbell
2021. 6. 26. 23:56
직렬화(Serialize)
- 자바 시스템 내부에서 사용되는 Object 또는 Data를 외부의 자바 시스템에서도 사용할 수 있도록 byte 형태로 데이터를 변환하는 기술.
- JVM(Java Virtual Machine 이하 JVM)의 메모리에 상주(힙 또는 스택)되어 있는 객체 데이터를 바이트 형태로 변환하는 기술
역직렬화(Deserialize)
- byte로 변환된 Data를 원래대로 Object나 Data로 변환하는 기술을 역직렬화(Deserialize)라고 부릅니다.
- 직렬화된 바이트 형태의 데이터를 객체로 변환해서 JVM으로 상주시키는 형태.
직렬화방법에는 여러 Format이 존재합니다.
- 표형태의 다량의 데이터를 직렬화할때는 CSV형태
Member member = new Member("김배민", "deliverykim@baemin.com", 25);
// member객체를 csv로 변환
String csv = String.format("%s,%s,%d",member.getName(), member.getEmail(), member.getAge());
System.out.println(csv);
- 구조적인 데이터는 XML, JSON형태.
- no 라이브러리
Member member = new Member("김배민", "deliverykim@baemin.com", 25);
// member객체를 json으로 변환
String json = String.format(
"{\"name\":\"%s\",\"email\":\"%s\",\"age\":%d}",
member.getName(), member.getEmail(), member.getAge());
System.out.println(json);
- Jackson
// 직렬화
ObjectMapper mapper = new ObjectMapper();
String jsonResult = mapper.writeValueAsString(json으로 바꾸고싶은 java객체);
// 역직렬화
String jsonInput = "json 데이터";
ObjectMapper mapper = new ObjectMapper();
Example exam = mapper.readValue(jsonInput, Example.class);
- Gson
// 직렬화
String jsonResult = new Gson().toJson(json으로 바꾸고싶은 java객체);
// 역직렬화
String jsonInput = "json 데이터";
Example exam = new Gson().fromJson(jsonInput, Example.class);
어디에 사용되는가?
서블릿 세션 (Servlet Session)
- 세션을 서블릿 메모리 위에서 운용한다면 직렬화를 필요로 하지 않지만, 파일로 저장하거나 세션 클러스터링, DB를 저장하는 옵션 등을 선택하게 되면 세션 자체가 직렬화가 되어 저장되어 전달됩니다.
캐시 (Cache)
- Ehcache, Redis, Memcached 라이브러리 시스템을 많이 사용됩니다.
자바 RMI(Remote Method Invocation)
- 원격 시스템 간의 메시지 교환을 위해서 사용하는 자바에서 지원하는 기술.
자바의 직렬화 단점?
1. 역직렬화시 클래스 구조 변경 문제
특정 클래스를 직렬화한 뒤
해당 클래스의 변경이 발생하였을 때
역직렬화를 진행하면 java.io.InvalidClassException이 발생
이를 막기 위해서 모델의 버젼간의 호환성을 유지하기 위해서는 SUID(serialVersionUID)를 정의해야합니다.
ex)
import java.io.Serializable;
public class Person implements Serializable {
private static final long serialVersionUID = -5129628467395047900L;
String name;
int age;
double height;
String hobby;
}
2. 직렬화 Data Size 문제
간단한 객체의 내용도 직렬화시 2배이상의 차이
- 메모리기반의 Cache에서는 Data를 저장할 수 있는 용량의 한계가 있기 때문에 Json 형태와 같은 경량화된 형태로 직렬화하는 것도 좋은 방법
정리
- 외부 저장소로 저장되는 데이터는 짧은 만료시간의 데이터를 제외하고 자바 직렬화를 사용을 지양합니다.
- 역직렬화시 반드시 예외가 생긴다는 것을 생각하고 개발합니다.
- 자주 변경되는 비즈니스적인 데이터를 자바 직렬화을 사용하지 않습니다.
- 긴 만료 시간을 가지는 데이터는 JSON 등 다른 포맷을 사용하여 저장합니다.
사용 경험
Spring Framework(boot, webflux)과 Redis 연동
- String, String
@Configuration
public class BasicRedisConfig {
...
@Primary
@Bean
ReactiveRedisOperations<String, String> redisOperations(ReactiveRedisConnectionFactory factory) {
RedisSerializer<String> serializer = new StringRedisSerializer();
RedisSerializationContext<String, String> serializationContext = RedisSerializationContext
.<String, String>newSerializationContext()
.key(serializer)
.value(serializer)
.hashKey(serializer)
.hashValue(serializer)
.build();
return new ReactiveRedisTemplate<>(factory, serializationContext);
}
}
- String, Oject
@Configuration
public class RedisConfig {
@Value("${spring.redis.port}")
public int port;
@Value("${spring.redis.host}")
public String host;
@Autowired
public ObjectMapper objectMapper;
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setConnectionFactory(connectionFactory);
return redisTemplate;
}
@Bean
public RedisConnectionFactory redisConnectionFactory() {
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setHostName(host);
redisStandaloneConfiguration.setPort(port);
return new LettuceConnectionFactory(redisStandaloneConfiguration);
}
}
Reference
https://woowabros.github.io/experience/2017/10/17/java-serialize2.html