[Springboot] Entity에 Serializable 구현을 해야 하나?

송진영·2023년 8월 8일
0

Springboot

목록 보기
9/9

대기업 멘토분께 멘토링을 받는 기회가 있었을 때, 코드 리뷰를 부탁드렸더니 Spring 사용한 지 얼마 안됐냐는 말을 들었다.. 당시 시간에 쫓겨 기초적인 부분들을 많이 빼먹고, 구현을 했었는데 그 중 하나가 Entity에 Serializable을 구현하지 않은 것이었다. 당시 나는 Serializable을 처음 들어 혼란스러웠다.

@Entity
@Table(name="boards")
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Boards implements Serializable {
    @JsonIgnore
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", nullable = false)
    private Long id;
    @Column(name = "user_id", nullable = false)
    private Long userId;
    @Column(name = "title", nullable = false)
    private String title;
    @Column(name = "content", nullable = false)
    private String content;
}

Serializable이란?

Serializable 인터페이스는 자바에서 객체의 직렬화(Serialization)을 지원하기 위한 인터페이스이다. 직렬화란 객체를 바이트 스트림으로 변환하여 저장하거나 네트워크 상에서 전송할 수 있는 형태로 변환하는 과정을 말한다.

Serializable 인터페이스를 구현한 클래스는 자바의 직렬화 기능을 활용할 수 있게 된다. 직렬화된 객체는 파일에 저장하거나 네트워크를 통해 전송할 때 사용될 수 있다. 이를 통해 객체의 상태를 보존하고, 다른 시스템 간에 객체를 공유하거나 전송할 수 있다.

Serializable을 사용하는 경우

1. 엔티티의 연관 관계:

  • Entity 클래스는 데이터베이스의 테이블과 매핑되는 클래스로, 연관 관계나 데이터베이스에서의 특정 상태를 나타내는데 사용된다.
  • DTO는 특정 Use Case에 따라 필요한 데이터만을 담고 있는 객체로, 엔티티의 일부 정보만을 가지고 오거나 변형하여 클라이언트로 전달하는 역할을 수행한다.
  • 하지만 Entity 클래스가 직렬화 가능해야 하는 이유는 연관 관계에 의해 다른 엔티티들과 연결되어 있을 수 있기 때문이다. 이런 연관 관계가 있는 경우에도 직렬화를 위해 Serializable 인터페이스를 구현하는 것이 필요할 수 있다.

2. 분산 시스템에서의 사용:

분산 시스템이나 마이크로서비스 아키텍처에서도 엔티티 클래스를 직렬화하여 전달하는 경우가 있다.
예를 들어 서로 다른 서비스 간에 데이터를 주고받거나 공유해야 할 때, 엔티티 클래스가 직렬화되어야 해당 객체의 상태를 전달할 수 있다.

3. 잠재적인 사용 시나리오 변화:

현재는 DTO를 통해 전달하더라도 나중에 시스템 확장이나 다른 용도로 Entity 클래스를 직접 전달하는 경우가 발생할 수 있다.
이런 경우를 대비하여 Entity 클래스를 미리 직렬화 가능하도록 준비해두는 것이 유용할 수 있다.

Serializable을 사용하지 않았을 때 발생할 수 있는 문제

직렬화를 하지 않고, 객체를 보내거나 받을 때는 버전이나 환경에 역직렬화 과정에서 문제가 발생할 수 있다. 역직렬화 과정에서 주의해야 할 몇 가지 문제점은 다음과 같다.

1. 버전 불일치:

  • 객체를 직렬화 할 때 클래스의 버전 정보('serialVersionUID')가 포함된다. 역직렬화 과정에서는 클래스 버전이 서로 일치해야 한다.
  • 클래스의 내용이 변경되거나 버전이 다르다면 역직렬화에 실패할 수 있다. 이로 인해 'java.io.InvalidClassException' 예외가 발생할 수 있다.

2. 환경의 차이:

  • 객체를 직렬화한 환경과 역직렬화하는 환경이 다를 경우 문제가 발생할 수 있다.
  • 예를 들어 서로 다른 JDK 버전을 사용하는 경우나 클래스 패스에 클래스가 존재하지 않는 경우 등에 역직렬화 과정에서 예외가 발생할 수 있다.

3. 직렬화 포함 여부:

  • 직렬화를 구현하지 않은 클래스의 객체를 직렬화하려고 할 떄는 역직렬화 과정에서 'java.io.NotSeriializableException' 예외가 발생한다.

Serializable을 사용하지 않아도 되는 이유

위의 내용을 보면 Serializable을 사용해야 할 것 같지만 김영한 님도 실용적인 관점에서는 Serializable을 거의 사용하지 않는다고 하셨다.
인프런 김영한님 담변
하지만 JPA 표준 스펙은 Entity에 Serializable을 구현하도록 되어 있다곤 했다.

1. DTO, VO의 사용:
요즘 구현을 할 때 DTO, VO를 사용하지 않고, Entity 자체를 보내는 경우는 거의 없다.

2. 직렬화 대안 기술:

  • Spring boot와 MSA 환경에서는 JSON, XML 등의 직렬화 대안 기술을 활용하여 데이터를 주고 받는 것이 일반적이다.
  • JSON을 사용하는 경우 Jackson 라이브러리가 자동으로 객체를 JSON으로 변환하고 역직렬화한다. 이 경우 클래스 버전과 환경의 일치성을 걱정할 필요가 없을 수 있다.

3. 클래스 로딩 및 Classpath 관리:

  • Spring boot와 MSA 환경은 클래스 로딩과 Classpath 관리를 편리하게 제공한다.
  • 필요한 클래스들을 각 마이크로서비스의 패키지 구조에 잘 배치하고, 의존성 관리를 해주면, 클래스 버전 및 환경의 불일치 문제를 최소화할 수 있다.

4. 마이크로서비스 아키텍처의 장점:

  • MSA 환경에서는 각 서비스가 독립적으로 배포되고 실행되므로, 클래스나 환경의 변경이 각 서비스에 미치는 영향이 제한적일 수 있다.
  • 이로 인해 클래스나 환경의 변화로 인한 문제가 다른 서비스로 전파되는 것을 최소화할 수 있다.

결론

실무적인 관점에서 웬만한 문제로는 Serializable을 사용하지 않아 발생하는 문제는 거의 없어서 사용하지 않아도 된다. 하지만 JPA 표준에서도 권장을 하고, 혹시 발생할 문제가 있을 수 있기 때문에 사용하는 게 낫지 않을까 싶다.

profile
못하는 건 없다. 단지 그만큼 노력을 안 할 뿐이다.

1개의 댓글

comment-user-thumbnail
2023년 8월 8일

좋은 글 감사합니다.

답글 달기