2015-09-18 3 views
7

Я узнал, что Hibernate не возвращает экземпляр вашего фактического класса сущности, когда он дает результат запроса, но вместо этого возвращает экземпляр «прокси», который динамически подклассифицировано из класса вашего фактического объекта. Я понимаю причину такого поведения, поскольку он позволяет реализовать ленивую инициализацию. Тем не менее, у меня есть несколько вопросов, без ответа на деталях реализации этих прокси-классы:Hibernate: подробности реализации прокси (Lazy Fetching)

  1. Будет ленивое неправдоподобное поле загружаются только когда я использую добытчик? Что делать, если я использую поле в, скажем, моем методе equals или hashCode? Будут ли выполняться эти методы в NullPointerException, если я еще не назвал получателя этого поля?

  2. Как именно Hibernate инициализирует поле при его инициализации? Выполняет ли он метод настройки поля, который я определил в классе сущности, или присваивает значение непосредственно переменной, посредством отражения или что-то в этом роде?

ответ

1

Во-первых, два правила:

  1. Доверенные делегат все неконечное вызовы методов целевого экземпляра, за исключением метода для получения идентификатора, если доступ к свойству для идентификатора определяется в отображениях.
  2. Объекты прокси-объекта: never Инициализирован, экземпляр объекта инициализирован.

1) Предположим, что вы вызываете a.equals(b) где оба a и b являются прокси одного и того же лица. И давайте говорить, что equals метод реализуется следующим образом:

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

Метод aequals делегирован целевой экземпляр форсирования его полная инициализации. Таким образом, вы небезопасны относительно полей в экземпляре a (вы можете использовать их напрямую).

Однако доступ к полям непосредственно в b (например other.someField) является никогда действует. Не имеет значения, инициализирован ли b или нет, экземпляр прокси никогда не инициализируется, а только целевой экземпляр. Итак, someField всегда null в примере b.

Правильная реализация является использование методов получения, по крайней мере для other например:

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

или быть последовательным:

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

вещи разные, когда речь идет о final методов - Hibernate не может переопределить их для делегирования вызова целевой. Итак, если метод equals был в final в предыдущем примере, вы получите NullPointerException при доступе к this.someField.

Все это можно избежать, настроив Hibernate на использование инструментария байт-кода вместо прокси-серверов, но у этого есть свои собственные подводные камни и он не принят широко.

2) Опять же, он никогда не инициализирует экземпляр прокси. Когда дело доходит до инициализации целевого экземпляра, это зависит от того, определяется ли поле или доступ к свойствам в сопоставлениях. В обоих случаях используется рефлексия (для назначения значений непосредственно полям в случае доступа к полю или для вызова сеттеров в случае доступа к свойствам).

Смежные вопросы