[Java] Why - JPA에서 기본 생성자가 반드시 필요한 이유. (with Reflection API)

하쮸·2024년 11월 22일

Error, Why, What, How

목록 보기
4/65

이전에 팀프로젝트 할 때도 그렇고 이번에 JPA를 사용해서 공부하던 도중 기본 생성자가 없어서 에러가 발생.
"도대체 왜 기본 생성자가 필요한걸까?" 의문이 생김.
이랬던 적이 한 두번이 아니라 관련내용을 정리를 한 글.


1. 기본 생성자.

public 클래스이름() {
    
}
  • 기본 생성자(Default Constructor)
    • 매개변수가 없는 생성자를 기본 생성자라 함.
    • 생성자가 하나도 없을 경우 자바 컴파일러가 매개변수가 없고 {}안 아무것도 없는 기본 생성자를 자동으로 만들어줌. (생략되어 있음.)
      • 단, 생성자가 하나라도 있다면 기본 생성자가 생성되지 않음.
    • 자동으로 생성된 기본 생성자는 클래스와 같은 접근 제어자를 가짐.

2. Reflection API

  • Reflection API란?
    • Reflection API는 클래스의 구체적인 타입을 알지 못해도 해당 클래스의 메서드, 필드, 생성자 등의 정보를 런타임에 동적으로 가져오거나 접근할 수 있는 Java API.
      • 접근 제어자와 상관 없이 클래스 객체를 동적으로 생성(런타임 시점).
    • 이미 로딩이 완료된 클래스에서 또 다른 클래스를 동적으로 로딩(Dynamic Loading)하여 생성자(Constructor), 멤버 필드(Member Variables) 그리고 멤버 메서드(Member Method) 등을 사용할 수 있도록 함.
      • 즉, 컴파일 시간(Compile Time)이 아니라 실행 시간(Run Time)에 동적으로 특정 클래스의 구조를 분석하고 활용할 수 있는 기능.
        • 자바는 컴파일러를 사용하고, 컴파일 시점에 타입이 결정됨.

2-1. 원리.

  • 자바에서는 JVM이 실행되면 코드가 컴파일러를 거쳐 바이트 코드로 변환되어 static 영역에 저장되는데 Reflection API는 이 정보를 활용함.

2-2. 단점.

  • 성능 문제, 메모리 낭비.
    • 컴파일 시점이 아닌 런타임에 동적으로 타입을 분석하고 정보를 가져오므로 JVM을 최적화할 수 없기 때문.
  • 캡슐화, 추상화 깨지는 문제. (접근 제어자 무시)

2-3. 사용처.

  • 프레임워크나 라이브러리에서 주로 사용됨.
    • 프레임워크나 라이브러리는 사용자가 어떤 클래스를 만들지 예측할 수 없기 때문에 동적으로 해결해주기 위해 Reflection을 사용.
    • Ex intellij의 자동완성, jackson 라이브러리, Hibernate Spring Framework
      • 스프링 프레임워크의 경우 대표적인 예시로 Spring Container의 BeanFactory.
      • Bean은 애플리케이션이 실행한 후 런타임에 객체가 호출될 때 동적으로 객체의 인스턴스를 생성하는데 이때 Spring Container의 BeanFactory에서 리플렉션을 사용

3. JPA

  • JPAEntity로 사용할 객체에 반드시 기본 생성자가 있어야 됨.
    • JPA 에서 Entity에 기본 생성자가 필요한 이유가 동적으로 객체 생성 시 Reflection API를 활용하기 때문임.
      • 왜냐하면 Reflection API로 가져올 수 없는 정보 중 하나가 생성자의 인자 정보.
      • 그래서 기본 생성자가 반드시 있어야 객체를 생성할 수 있음.
        • 기본 생성자로 객체를 생성만 하면 필드 값 등은 Reflection API로 넣어줄 수 있음.
    • 기본 생성자 없이 사용자가 만들어놓은 파라미터가 있는 생성자만 존재한다면 Java Reflection이 객체를 생성할 수 없게 됨.

4. 추가내용.

  • Almost all frameworks require a default(no-argument) constructor in your class because these frameworks use reflection to create objects by invoking the default constructor
    • 거의 모든 프레임워크는 클래스에 기본 생성자(인자가 없는 생성자)를 요구합니다.
      이유는 이러한 프레임워크들이 기본 생성자를 호출하여 객체를 생성하기 위해 Reflection을 사용하기 때문입니다.

김영한님의 인프런 강의 : 자바 ORM 표준 JPA 프로그래밍.

  • 이렇게 기본 생성자가 없더라도 실행되는 경우가 있는데 해당 질문에 대한 김영한님의 답변을 참고.

  • 하이버네이트는 내부적으로 Class.newInstance()라는 리플렉션을 이용해 해당 Entity의 기본 생성자를 호출해서 객체를 생성하는데 이 리플렉션은 생성자의 매개변수를 읽을 수가 없어서 반드시 기본 생성자를 정의해야함.
    • 항상 기본 생성자를 정의해야 하는 것은 아니고 아래의 코드처럼 매개변수가 있는 생성자를 정의했을 때만 기본 생성자를 생성해주면 됨.
public User(String name) {
	this.name = name;
}
  • 만약 매개변수가 있는 생성자를 정의하지 않았다면 자바에서 자동으로 기본 생성자를 생성하기 때문에 따로 기본 생성자를 정의하지 않아도 됨.

5. 기타.

  • 컴파일 시점에 타입을 결정.(정적 언어) : Java, C, C++, Go 등등

    • 컴파일 : 작성한 코드를 기계어로 변환하여 실행가능한 프로그램으로 변환시키는 과정을 컴파일, 컴파일이 이루어지는 시간을 컴파일 타임.
  • 런타임 시점에 타입을 결정(동적 언어) : Python, PHP, JavaScript, Ruby 등등

    • 런타임 : 컴파일이 끝난 프로그램이 실행되고, 이러한 응용프로그램이 실행되고 있는 걸 런타임(Runtime).

6. Ref

profile
Every cloud has a silver lining.ㅤㅤㅤㅤㅤㅤㅤㅤㅤhttps://www.instagram.com/ha_jju

0개의 댓글