📜 ⬆️ ⬇️

Hibernate: using lazy initialization in developing a client-server application

When designing domains of an application developed using Hibernate, the developer must make a choice: whether to initialize domain properties corresponding to collections of related domains immediately (FetchType = EAGER) or to do it only when accessing them (FetchType = LAZY). In fact, in the case when the domain has any complex structure of connections between objects, the choice has already been made - to load a half base for the sake of a single object, as would be the case with FetchType = EAGER, to put it mildly, unwise. Therefore, lazy initialization in the case of collections is the most preferred strategy for initializing related objects.

However, not all so simple. Lazy initialization is implemented by creating a proxy object using the JDK Dynamic Proxy or the CGLIB library. In both cases, proxying the corresponding getter methods is reduced to accessing the Hibernate session to obtain the necessary data. The latter, in turn, means that access to the lazy properties of an object can only be implemented if there is a Hibernate session. Otherwise, an attempt to obtain an object property will result in the unforgettable exception “LazyInitializationException: could not initialize the proxy - the owning Session was closed”.


It is clear that it is not always possible to have an open session at hand, which causes some inconvenience. So, for example, in order to use domains with lazy initialization in MVC application templates, you will have to resort to the “ OpenSessionInView ” method, the essence of which is to create a filter that ensures opening a session at the beginning of the request and closing it at the end.
')
But, what to do if the domains with the loaded data need to be used outside the Hibernate session? For example, in the case of a client-server architecture, when does the server need to transfer domains to a client? Of course, the opening of a session on the client’s side is out of the question, if only because in the general case it knows nothing about the database. The only way out of the situation, in my opinion, would be “deproxing” domain objects and initializing them with the necessary data before transferring it from the server to the client.

Imagine that the server part of the application consists of 3 layers:

The domain classes themselves are accessible both to the server and to the client (which is, in general, logical).

In this scenario, the business logic layer can easily work with domain proxies during the Hibernate session. The role of the services layer is reduced to obtaining the necessary data from the business logic layer and data composition for the client: creating DTO objects based on domain classes by copying a certain depth and detail.

The question remains only how to conduct this “deproxing”. In principle, this can be done using Hibernate itself :

public static <T> T initializeAndUnproxy(T entity) {
if (entity == null ) {
throw new
NullPointerException( "Entity passed for initialization is null" );
}

Hibernate.initialize(entity);
if (entity instanceof HibernateProxy) {
entity = (T) ((HibernateProxy) entity).getHibernateLazyInitializer()
.getImplementation();
}
return entity;
}

* This source code was highlighted with Source Code Highlighter .


This approach initializes all the collections of a given object and “gets” it from the proxy. However, it has a number of flaws: all collections are initialized in a row and only the parent object is deproxed (at least because it is not clear how deeply to go down the object's connection graph when deproxing).

The solution in this situation can be the creation of a small utility class, which will depress the domain by creating a new object of the same class and initializing the properties corresponding to the base classes of Hibernate . All other object properties will be initialized by the services layer as needed.

I do not undertake to assert that this approach is optimal and / or the only true. If you have any suggestions how to solve the problem differently, I will be glad to hear them.

Source: https://habr.com/ru/post/111911/


All Articles