2015-09-18 14 views
7

Dowiedziałem się, że Hibernate nie zwraca instancji twojej rzeczywistej klasy encji, gdy daje wynik zapytania, ale zamiast tego zwraca instancję "proxy", która jest dynamicznie podklasowane z klasy twojej rzeczywistej jednostki. Rozumiem powód tego zachowania, ponieważ pozwala on na realizację leniwego inicjowania. Mam jednak kilka pytań pozostało bez odpowiedzi o szczegółach realizacji tych klas proxy:Hibernate: Szczegóły implementacji proxy (Lazy Fetching)

  1. Czy leniwy pole idące ładowane tylko wtedy, kiedy używać getter? Co się stanie, jeśli użyję pola w, powiedzmy, metodzie equals lub hashCode? Czy wykonanie tych metod spowoduje, że NullPointerException, kiedy nie nazwałbym gettera tego pola wcześniej?

  2. W jaki sposób Hibernate inicjalizuje pole po uruchomieniu inicjowania? Czy wykonuje on metodę ustawiającą pola, którą zdefiniowałem w klasie encji, czy też przydzieli wartość bezpośrednio do zmiennej, poprzez odbicie lub coś w tym stylu?

Odpowiedz

1

pierwsze, dwie zasady:

  1. Prokurenci delegat wszystko zakaz ostateczna metoda zwraca się do instancji docelowej, z wyjątkiem sposobu uzyskania identyfikatora jeśli dostęp nieruchomość za id jest zdefiniowany w odwzorowań.
  2. Instancje obiektu proxy są nigdy zainicjowane, instancja docelowa jest zainicjowana.

1) Załóżmy, że powołują a.equals(b) gdzie zarówno a i b są prokurenci tego samego podmiotu. I powiedzmy, że equals metoda jest realizowany tak:

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

equals metoda a jest delegowana do instancji docelowej zmuszając pełnej inicjalizacji. Więc jesteś bezpieczny w odniesieniu do pól w instancji a (możesz ich użyć bezpośrednio).

jednak dostęp do pól bezpośrednio w instancji b (other.someField) jest nigdy ważny. Nie ma znaczenia, czy b jest zainicjowany, czy nie, instancja proxy nigdy nie jest inicjowana, a jedynie instancja docelowa. Tak więc someField jest zawsze null w instancji b.

Prawidłowa realizacja jest użycie pobierające przynajmniej dla other przykład:

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

lub być zgodne:

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

są różne rzeczy, jeśli chodzi o final metod - Hibernate nie może nadpisuj je, aby przekazać połączenie do celu. Tak więc, jeśli w poprzednim przykładzie metoda equals byłaby final, otrzymasz NullPointerException podczas uzyskiwania dostępu do this.someField.

Wszystko to można uniknąć, konfigurując Hibernate, aby używał oprzyrządowania bajtowego zamiast serwerów proxy, ale ma on własne pułapki i nie jest powszechnie stosowany.

2) Ponownie, nigdy nie inicjuje samej instancji serwera proxy. W przypadku inicjowania instancji docelowej zależy to od tego, czy w odwzorowaniach jest zdefiniowany dostęp do pola lub właściwości. W obu przypadkach używane jest odbicie (przypisanie wartości bezpośrednio do pól w przypadku dostępu do pola lub do wywołania seterów w przypadku dostępu do właściwości).