2015-09-18 6 views
7

Ich habe gelernt, dass Hibernate keine Instanz Ihrer tatsächlichen Entitätsklasse zurückgibt, wenn es Ihnen das Ergebnis einer Abfrage gibt, sondern stattdessen eine 'Proxy' Instanz, die dynamisch ist Unterklassifiziert von der Klasse Ihrer tatsächlichen Entität. Ich verstehe den Grund für dieses Verhalten, dass es die Realisierung der faulen Initialisierung ermöglicht. Allerdings habe ich ein paar Fragen offen über die Einzelheiten der Durchführung dieser Proxy-Klassen:Hibernate: Details der Proxyimplementierung (Lazy Fetching)

  1. Wird die faul geholt Feld bekommen nur geladen, wenn ich den Getter verwenden? Was passiert, wenn ich das Feld beispielsweise in meiner Methode equals oder hashCode verwende? Wird die Ausführung dieser Methoden zu einem NullPointerException führen, wenn ich den Getter dieses Feldes vorher nicht aufgerufen habe?

  2. Wie genau initialisiert Hibernate das Feld, wenn seine Initialisierung ausgelöst wird? Führt es die Setter-Methode des Felds aus, die ich in der Entitätsklasse definiert habe, oder wird es den Wert direkt der Variablen über Reflektion oder etwas Ähnliches zuweisen?

Antwort

1

Zuerst werden zwei Regeln:

  1. Proxies Delegierten alle nicht endgültige Methode Aufrufe an die Zielinstanz, mit Ausnahme der Methode für id bekommen, wenn Eigentum Zugang für ID in den Zuordnungen definiert ist.
  2. Proxy-Objektinstanzen sind nie initialisiert, die Zielinstanz wird initialisiert.

1) Angenommen, Sie a.equals(b) berufen, wo sowohl a und b Proxies von derselben Einheit sind. Und können sagen, dass equals Methode wie folgt implementiert:

public boolean equals(Object other) { 
    ... 
    if (this.someField.equals(other.someField)) { 
    ... 
    } 
    ... 
} 

Die equals Methode der a auf die Zielinstanz zwingt seine volle Initialisierung delegiert. So sind Sie in Bezug auf die Felder in der a Instanz sicher (Sie können sie direkt verwenden).

jedoch in dem b Beispiel die Felder direkt Zugriff (other.someField) ist nie gültig. Es spielt keine Rolle, ob b initialisiert wird oder nicht, die Proxy-Instanz wird niemals initialisiert, nur die Zielinstanz. So ist someField immer null in der b Instanz.

Die korrekte Implementierung ist für other Instanz Getter mindestens zu verwenden:

this.someField.equals(other.getSomeField()) 

oder konsistent sein:

this.getSomeField().equals(other.getSomeField()) 

Anders sieht es aus, wenn es um final Methoden kommt - Hibernate kann nicht überschreiben Sie sie, um den Anruf an das Ziel zu delegieren. Wenn also im vorherigen Beispiel die equals-Methode final ist, erhalten Sie beim Zugriff auf this.someField eine NullPointerException.

All dies kann vermieden werden, indem Hibernate für die Verwendung von Bytecode-Instrumentierung anstelle von Proxies konfiguriert wird, die jedoch ihre eigenen Fallstricke hat und nicht weit verbreitet ist.

2) Erneut wird die Proxy-Instanz selbst nie initialisiert. Wenn es um die Initialisierung der Zielinstanz geht, hängt es davon ab, ob der Feld- oder Eigenschaftszugriff in den Zuordnungen definiert ist. In beiden Fällen wird die Reflektion verwendet (um Felder im Falle eines Feldzugriffs direkt Feldern zuzuordnen oder Setter beim Zugriff auf Eigenschaften aufzurufen).

Verwandte Themen