hibernate Proxy
hibernate Proxy
https://www.baeldung.com/hibernate-proxy-load-method
a proxy is “a function authorized to act as the deputy or substitute for another”.
This applies to Hibernate when we call Session.load() to create what is called an uninitialized proxy of our desired entity class.
Hibernate subclasses our entity class, using the CGLib library. Other than the @Id method, the proxy implementation delegates all other property methods to the Hibernate session to populate the instance, somewhat like:
public class HibernateProxy extends MyEntity {
private MyEntity target;
public String getFirstName() {
if (target == null) {
target = readFromDatabase();
}
return target.getFirstName();
}
}
public class HibernateProxy extends MyEntity { |
Proxy and Lazy loading
Eg Employee albert = session.load(Employee.class, new Long(1));
Hibernate will create an uninitialized proxy of Employee. It will contain the ID that we gave it but otherwise will have no other values because we haven't hit the database yet.
once we call a method on albert:String firstName = albert.getFirstName();
Then Hibernate will query the employee database table for an entity with a primary key of 1, populating albert with his properties from the corresponding row.
one to many
|
we only queried for the company row, but the proxy will leave the employee set alone until we call getEmployees depending on the fetching strategy.
eager loading
using get
bypass proxies entirely and ask Hibernate to load the real thing using Session.get():
mployee finnigan = session.get(Employee.class, new Long(6)); ,
Will call the database right away, instead of returning a proxy.
While get() is convenient, load() can be lighter on the database.
Employee gerald = session.get(Employee.class, new Long(7)); |
Since we know that we are only going to change the employee record in this situation, calling load() for Company is sensible.
The Proxy class is generated at runtime and it extends the original entity class. Hibernate uses Proxy objects for entities is for to allow lazy loading.
When accessing basic properties on the Proxy, it simply delegates the call to the original entity.
Every List
, Set
, Map
type in the entity class is substituted by a PersistentList
, PersistentSet
, PersistentMap
. These classes are responsible for intercepting a call to an uninitialized collection.
The Proxy doesn't issue any SQL statement. It simply triggers an InitializeCollectionEvent, which is handled by the associated listener, that knows which initialization query to issue (depends on the configured fetch plan).
https://xebia.com/blog/advanced-hibernate-proxy-pitfalls/
Proxies are the mechanism that allows Hibernate to break up the interconnected cloud of objects in the database into smaller chunks, that can easily fit in memory.
Pojo
public class Person { |
table rows
PERSON | ||
---|---|---|
ID | NAME | BOSS |
1 | Daan | NULL |
2 | Vincent | 1 |
3 | Eelco | 1 |
4 | Jan | 2 |
5 | Maarten | 3 |
6 | Erik | 3 |
if Hibernate loads the row with NAME=’Maarten’?
To store the data in memory, Hibernate will create a new Person object and set the columns to the fields. It stores the ID column in the id field and the NAME column in the name field.
Coming to the BOSS column, Hibernate faces a problem: The type of the column is NUMERIC, but the type of the property is Person. This is of course a foreign key, to another row in the PERSON table. Now, Hibernate could simply load the data from the associated row and create a new Person object and store it in the field, but this would cascade eventually to all rows in the table (and possibly other tables in the database), especially taking into account the employees property as well.
nstead of loading the associated row, Hibernate will create a Person object and set the id property to the value found in the BOSS column. This Person object is a specialized Person object, that will load the associated data if necessary. Initially the fields of this new Person object are not set, since the data is not yet loaded. When a method is invoked on the object, Hibernate will fetch the data from the column and populate the object. This is the proxy mechanism.

Hibernate will create a dynamic subclass of Person using CGLib and add the desired functionality. We need a subclass of Person here, to comply with the type of the boss field.
Hibernate proxy can be easily identified by the class name, which will contain the “\(EnhancerByCGLIB\)” marker. This is due to the fact that the class is generated at runtime by CGLib.

The most important is CGLIB$CALLBACK_0, which is set to an instance of CGLIBLazyInitializer, which is a Hibernate class. This is the object that enables the proxy to load the data when needed. It contains a “target” field, that will contain the Hibernate loaded object when the data is loaded
bytecode instrumentation
The bytecode enhancement can happen at:
Build-time
After the hibernate entities are compiled, the build tool (e.g. ANT, Maven) will insert bytecode level instructions into each compiled entity class. Because the classes are enhanced at build-time, this process exhibits no extra runtime penalty. Testing can be done against enhanced class versions, so that the actual production code is validated before the project gets built.
Runtime
The runtime weaving can be done using:
- A Java agent, doing bytecode enhancement upon entity class loading
- A runtime container (e.g. Spring), using JDK Instrumentation support
eg hibenate dirty check
Every time an entity is loaded, Hibernate makes an additional copy of all entity property values. At flush time, every managed entity property is matched against the loading-time snapshot value:
A more efficient approach would be to mark dirty properties upon value changing. Analogue to the original deep comparison strategy, it’s good practice to decouple the domain model structures from the change detection logic. The automatic entity change detection mechanism is a cross-cutting concern, that can be woven either at build-time or at runtime.
The entity class can be appended with bytecode level instructions implementing the automatic dirty checking mechanism.