[java] Hibernate는 왜 인자 생성자를 필요로하지 않습니까?

인수가없는 생성자는 요구 사항입니다 (Hibernate와 같은 도구는이 생성자에 리플렉션을 사용하여 객체를 인스턴스화합니다).

나는 손으로 물결 모양의 대답을 얻었지만 누군가가 더 설명 할 수 있습니까? 감사



답변

Hibernate, 일반적으로 리플렉션을 통해 객체를 생성하는 코드는 Class<T>.newInstance()클래스의 새 인스턴스를 생성합니다. 이 메서드에는 개체를 인스턴스화 할 수있는 인수없는 공용 생성자가 필요합니다. 대부분의 사용 사례에서 인수가없는 생성자를 제공하는 것은 문제가되지 않습니다.

직렬화는 생성자를 호출하지 않고 객체를 생성하기 위해 jvm 매직을 사용하기 때문에 인수가없는 생성자가없는 문제를 해결할 수있는 직렬화 기반의 해킹이 있습니다. 그러나 이것은 모든 VM에서 사용할 수있는 것은 아닙니다. 예를 들어 XStream 은 인수없는 공개 생성자가없는 개체의 인스턴스를 만들 수 있지만 특정 VM에서만 사용할 수있는 소위 “향상된”모드에서 실행해야합니다. (자세한 내용은 링크를 참조하십시오.) Hibernate의 설계자는 확실히 모든 VM과의 호환성을 유지하기로 선택했기 때문에 이러한 트릭을 피하고 Class<T>.newInstance()인수가 필요없는 공식적으로 지원되는 리플렉션 방법을 사용합니다 .


답변

Hibernate는 개체를 인스턴스화합니다. 따라서 인스턴스화 할 수 있어야합니다. 인수가 없는 생성자가 없으면 Hibernate는 인스턴스화 하는 방법 , 즉 전달할 인수를 알지 못합니다 .

최대 절전 모드 설명서를 말한다 :

4.1.1. 인수가없는 생성자 구현

모든 퍼시 스턴트 클래스는 Hibernate가를 사용하여 인스턴스화 할 수 있도록 기본 생성자 (비공개 일 수 있음)를 가져야합니다 Constructor.newInstance(). Hibernate에서 런타임 프록시 생성을 위해 최소한 패키지 가시성을 가진 기본 생성자가있는 것이 좋습니다.


답변

Erm, 죄송하지만 Hibernate는 클래스가 매개 변수없는 생성자를 가져야한다고 요구 하지 않습니다 . JPA 2.0 사양 을 필요로하며, 이는 JPA를 대신하여 매우 절름발이입니다. JAXB와 같은 다른 프레임 워크도이를 필요로하며, 이러한 프레임 워크를 대신하여 매우 절망적입니다.

(사실 JAXB는 엔티티 팩토리를 허용한다고 가정하지만, 이러한 팩토리를 자체적으로 인스턴스화해야한다고 주장하며 , 내 책에서 팩토리를 허용하지 않는 것과 똑같이 좋은 매개 변수없는 생성자 를 필요로합니다 . !)

그러나 Hibernate는 그런 것을 요구하지 않습니다.

Hibernate는 인터 셉션 메커니즘 ( 문서의 “인터셉터” 참조 )을 지원하여 필요한 생성자 매개 변수로 객체를 인스턴스화 할 수 있습니다.

기본적으로 최대 절전 모드를 설정할 때 org.hibernate.Interceptor인터페이스를 구현하는 개체를 전달하면 최대 절전 모드가 instantiate()해당 개체의 새 인스턴스가 필요할 때마다 해당 인터페이스 의 메서드를 호출 하므로 해당 메서드의 구현은 new당신이 좋아하는 방식으로 당신의 물건.

나는 프로젝트에서 그것을 해왔고 그것은 매력처럼 작동합니다. 이 프로젝트에서는 가능할 때마다 JPA를 통해 작업을 수행하고 다른 옵션이 없을 때 인터셉터와 같은 Hibernate 기능 만 사용합니다.

Hibernate는 시작하는 동안 각 엔터티 클래스에 대한 정보 메시지를 발행하여 나에게 INFO: HHH000182: No default (no-argument) constructor for class및 라고 알려주기 때문에 다소 안전하지 않은 것처럼 보이지만 class must be instantiated by Interceptor나중에 인터셉터로 인스턴스화하고 만족합니다.

Hibernate 이외의 도구에 대한 질문의 “왜”부분에 답하기 위해 대답은 “절대적으로 정당한 이유가 없습니다”이며 이는 최대 절전 모드 인터셉터의 존재에 의해 입증됩니다. 클라이언트 개체 인스턴스화를위한 유사한 메커니즘을 지원할 수있는 도구가 많이 있지만 지원하지 않으므로 개체를 스스로 생성하므로 매개 변수없는 생성자가 필요합니다. 나는 이러한 도구의 제작자가 스스로를 무지한 응용 프로그램 프로그래머가 사용할 마법으로 가득 찬 프레임 워크를 만드는 닌자 시스템 프로그래머라고 생각하기 때문에 이런 일이 일어나고 있다고 믿고 있습니다. 다음과 같은 고급 구조가 필요합니다. 공장 패턴 . (괜찮아,그렇게 생각합니다. 나는 실제로 그렇게 생각 하지 않는다 . 장난이야.)


답변

최대 절전 모드는 필드 또는 속성 액세스 전략을 지원하는 ORM 프레임 워크입니다. 그러나 생성자 기반 매핑을 지원하지 않습니다. -같은 몇 가지 문제 때문에

클래스에 생성자가 많으면 어떻게 되나요 ?

public class Person {

    private String name;
    private Integer age;

    public Person(String name, Integer age) { ... }
    public Person(String name) { ... }
    public Person(Integer age) { ... }

}

보시다시피, Hibernate는 어떤 생성자가 호출되어야 하는지를 추측 할 수 없기 때문에 불일치 문제를 다룹니다. 예를 들어 저장된 Person 객체를 검색해야한다고 가정합니다.

Person person = (Person) session.get(Person.class, <IDENTIFIER>);

Person 객체를 검색하기 위해 Hibernate는 어떤 생성자를 호출해야합니까? 보이니?

마지막으로 리플렉션을 사용하여 Hibernate는 인수가 없는 생성자를 통해 클래스를 인스턴스화 할 수 있습니다. 그래서 전화 할 때

Person person = (Person) session.get(Person.class, <IDENTIFIER>);

Hibernate는 다음과 같이 Person 객체를 인스턴스화합니다.

Person.class.newInstance();

API 문서에 따르면

클래스는 마치 새로운 인수 목록이 표현식에

이야기의 교훈

Person.class.newInstance();

비슷하다

new Person();

다른 건


답변

실제로, 인수가없는 생성자가없는 클래스를 인스턴스화 할 수 있습니다. 클래스 생성자의 목록을 가져 와서 하나를 선택하고 가짜 매개 변수로 호출 할 수 있습니다.

이것이 가능하고 작동하고 문제가되지 않을 것이라고 생각하지만, 꽤 이상하다는 데 동의해야합니다.

Hibernate가하는 방식으로 객체를 생성하는 것 (나는 그것이 0-arg 생성자를 호출 한 다음 아마도 Reflection을 통해 인스턴스의 필드를 직접 수정한다고 믿습니다. 아마도 setter를 호출하는 방법을 알고있을 것입니다) 객체가 어떻게 생성되어야하는지에 약간 반대합니다 Java- 새 개체가 원하는 개체가되도록 적절한 매개 변수를 사용하여 생성자를 호출합니다. 객체를 인스턴스화 한 다음 변경하는 것은 다소 “안티 자바”(또는 안티 순수 이론적 자바)라고 생각합니다. 물론 직접 필드 조작을 통해이 작업을 수행하면 캡슐화 및 모든 멋진 캡슐화 작업이 진행됩니다. .

이 작업을 수행하는 적절한 방법은 적절한 생성자를 사용하여 데이터베이스 행의 정보에서 객체를 인스턴스화하는 방법을 Hibernate 매핑에서 정의하는 것이라고 생각합니다 … 그러나 이것은 더 복잡 할 것입니다. 더 복잡할수록 매핑이 더 복잡해지고 모두 더 “순수”합니다. 그리고 나는 이것이 현재의 접근 방식에 비해 이점이 없을 것이라고 생각합니다 ( “적절한 방식”으로 일하는 것에 대해 좋은 느낌을받는 것 외에는).

그렇게 말하고 Hibernate 접근 방식이 매우 “깨끗하지”않다는 것을 알면 0-arg 생성자를 갖는 의무가 엄격하게 필요하지는 않지만 순전히 “올바른 방식으로 수행했다고 생각하지만 요구 사항을 어느 정도 이해할 수 있습니다.” “근거, 그들이”적절한 방법 “(합리적 이유이기는하지만)에서 그보다 훨씬 전에 이탈했을 때.


답변

Hibernate는 (반영을 통해) 쿼리의 결과로 인스턴스를 생성해야합니다. Hibernate는이를 위해 엔티티의 인수가없는 생성자에 의존하므로 인수가없는 생성자를 제공해야합니다. 명확하지 않은 것은 무엇입니까?


답변

리플렉션을 통해 매개 변수없는 생성자로 객체를 생성 한 다음 리플렉션을 통해 데이터로 해당 속성을 채우는 것이 훨씬 쉽습니다. 이름 / 이름 충돌, 생성자 내부의 정의되지 않은 논리를 사용하여 매개 변수화 된 생성자의 임의 매개 변수에 데이터를 일치 시키려고 시도하는 것보다 개체의 속성과 일치하지 않는 매개 변수 집합 등.

리플렉션을 통해 매개 변수화 된 생성자는 매우 취약하고 매개 변수없는 생성자는 응용 프로그램에 안정성을 제공하고 개발자에게 개체 동작에 대한 제어를 제공하기 때문에 많은 ORM과 직렬 변환기에는 매개 변수없는 생성자가 필요합니다.