Hibernate 관리 객체에 대한 최종 필드를 선언하는 방법이 있습니까?
문제
나는 이제 막 Hibernate를 시작하고 있으며, 지금까지 내가 본 모든 예제는 Hibernate 문서에 있는 튜토리얼과 거의 비슷해 보입니다.
package org.hibernate.tutorial.domain;
import java.util.Date;
public class Event {
private Long id;
private String title;
private Date date;
public Event() {}
/* Accessor methods... */
}
구체적으로:어떤 필드도 다음과 같이 선언되지 않았습니다. final
, 그리고 Hibernate 프레임워크가 클래스를 인스턴스화하고 해당 필드를 설정할 수 있도록 인수 없는 생성자가 있어야 합니다.
하지만 문제는 이렇습니다 - 나는 정말 피할 수 있을 때마다 어떤 식으로든 내 클래스를 변경 가능하게 만드는 것을 좋아하지 않습니다(Java Practices:불변 객체는 이를 수행하는 데 매우 강력한 주장을 제시합니다.)그래서 각 필드를 '최종'으로 선언하더라도 Hibernate를 작동시킬 수 있는 방법이 있습니까??
나는 Hibernate가 클래스를 인스턴스화하기 위해 Reflection을 사용하므로 잘못된 생성자를 선택하거나 매개변수 중 하나에 잘못된 값을 전달할 위험을 감수하지 않고 일종의 생성자를 호출할 수 있어야 한다는 것을 이해합니다. 인수가 없는 생성자를 호출하고 각 필드를 한 번에 하나씩 설정합니다.그러나 불변 객체를 안전하게 인스턴스화할 수 있도록 Hibernate에 필요한 정보를 제공하는 것이 가능해야 하지 않나요?
public class Event {
private final Long id;
private final String title;
private final Date date;
public Event(@SetsProperty("id") Long id,
@SetsProperty("title") String title,
@SetsProperty("date") Date date) {
this.id = id;
this.title = title;
this.date = new Date(date.getTime());
}
/* Accessor methods... */
}
그만큼 @SetsProperty
주석은 물론 허구이지만 손이 닿지 않는 곳에는 없는 것 같습니다.
해결책
많은 운영이 변한 상태를 수행하기 때문에 최대 절전 모드의 사용 사례가 아닌 것 같습니다.
- 병합 객체
- 더러운 상태 점검
- 플러싱 변경
즉, 불변성에 대해 걱정한다면 사본 구성 요인과 함께 물체 주위에 포장지를 제공하도록 선택할 수 있습니다.
public class FinalEvent {
private final Integer id;
public FinalEvent(Event event) {
id = event.id;
}
}
그래도 추가 작업을 의미합니다.
이제 내가 생각하고 있으므로 최대 절전 모드 세션은 일반적으로 스레드 바운드 이며이 공간은 최종 필드의 이점 - 안전한 출판물입니다.
최종 필드의 다른 이점은 무엇입니까?
다른 팁
불변의 물체는 상태를 수정하는 방법이없는 객체 (즉, 필드)를 의미합니다. 필드는 최종적 일 필요는 없습니다. 따라서 모든 돌연변이터를 제거하고 액세서 대신 필드 ACCE를 사용하도록 최대 절전 모드를 구성하거나 무의미한 생성자와 돌연변이를 더 이상 표시 할 수 있습니다. 약간의 해결 방법이지만 아무것도 아닌 것보다 낫습니다.
실제로 JDK 1.5+에서는 최대 절전 모드가 최종 필드 변경을 (리플렉션을 통해) 처리할 수 있습니다.필드를 일부 기본값/null 등으로 설정하는 보호된 기본 생성자()를 만듭니다.Hibernate는 객체를 인스턴스화할 때 이러한 값을 재정의할 수 있고 재정의할 것입니다.
이는 모두 직렬화/역직렬화를 가능하게 하기 위해 만들어진 Java 1.5 메모리 모델의 변경 사항(최종값이 최종적이지 않도록 허용) 덕분에 가능합니다.
public class Event {
private final Long id;
private final String title;
private final Date date;
// Purely for serialization/deserialization
protected Event() {
id = null;
title = null;
date = null;
}
public Event(Long id, String title, Data date) {
this.id = id;
this.title = title;
this.date = date;
}
/* Accessor methods... */
}
이것은 오랫동안 나를 괴롭 혔습니다. 내가 최근에 시도한 한 가지 아이디어는 이것입니다 - 모델 클래스의 읽기 전용 인터페이스를 정의하고 DAO와 공장이 대신 대신에 반환하도록합니다. 즉, 구현이 변수가 변하지 않더라도 DAO/Factory 객체를 남겨두면 더 이상 조정할 수 없습니다.
그렇게 :
public interface Grape {
public Color getColor();
}
public class HibernateGrapeDao {
public Grape findGrape(int grapeId) {
HibernateGrape grape = hibernate.find(...
return grape;
}
}
class HibernateGrape implements Grape {
....
}
구현 클래스 패키지-프라이버시를 DAO 패키지로 유지하기를 원할 수도 있으므로 아무도 직접적으로 바이올린을 할 수 없습니다. 조금 더 많은 작업이지만 아마도 장기적으로 물건을 깨끗하게 유지하는 데 도움이됩니다. 그리고 분명히 전체 평등/정체성 사업에주의하십시오.
빌더 패턴을 사용하여 원하는 결과를 달성 할 수 있습니다. 나는 a를 읽었다 전기 얼마 전 최대 절전 모드 포럼에서 아이디어를 논의하는 (나는 직접 구현하지는 않았지만 ...)
@Access (accessType.field)로 수업을 주석에 넣으면 필드를 최종적으로 만들 수 있습니다. 이와 같이:
@Access(AccessType.FIELD)
public final class Event {
private final Long id;
private final String title;
private final Date date;
private Event() {
id = null;
title = null;
date = null;
}
public Event(Long id, String title, Date date) {
this.id = id;
this.title = title;
this.date = date;
}
}