This is an internal documentation. There is a good chance you’re looking for something else. See Disclaimer.
Hibernate is an implementation of the JPA specification, however we use the Hibernate API directly in many cases (instead of using the JPA API in the javax.persistence package), mostly because we need many custom Hibernate features to be able to provide exactly the same behaviour as the old Persistence API did.
Build the SessionFactory¶
The Hibernate bootstrapping process is documented here.
The SessionFactory should only be used internally by the
module. If other modules would use it directly, they could bypass the security layer.
Participate in the bootstrap process¶
It is possible for other modules to apply custom configuration options during the building of the session factory by contributing a HibernateBootstrapContribution. This contribution provides several methods to participate in various steps of the bootstrapping process. It’s also possible to provide a priority to control the execution order of the different contributions. This can for example be used for registering custom user types.
The main configuration is done by HibernateCoreBootstrapContribution.
The ContributionClassLoaderService is a custom ClassLoaderService which makes it easy to contribute services at runtime and to avoid having to use the ServiceLoader API used by the default implementation.
Register custom user extensions¶
Several user extensions are registered with the ContributionClassLoaderService:
For each custom user type a TypeContributor is contributed. There are some default types (for example
datetime) that are always registered, but other modules can contribute user types as well (see Custom user types).
Generate entity classes¶
Entity classes are generated based on the entity models and then registered with the provided MetadataSources.
Apply Hibernate properties¶
The next step is to apply the Hibernate configuration settings. The interface HibernatePropertiesProvider defines some common properties in a default method.
The only implementation (HibernatePropertiesProviderImpl) adds the connection options to the default properties. These are read from the application properties. The properties need to be transformed to a different format as Hibernate uses different options than HikariCP.
Injecting service factories¶
We use a custom implementation of PersisterFactory. This allows (manually) injecting services or contributions into a custom persister. Without using a custom factory, Hibernate just calls the default constructor.
A custom Hibernate Interceptor is registered as well. In order to be able to split up the functionality of the interceptor into different classes (perhaps from different modules) the DelegatingHibernateInterceptor is used (as it is not possible to register multiple interceptors). This class then delegates the events to the actual interceptor implementations.
Currently only one interceptor is used:
ValidationInterceptor which runs the entity validation before the changes are flushed to the database.
JDBC function registration¶
Event listener registration¶
Multiple Hibernate listeners (see EventType) are registered:
Startup time improvements¶
Hibernate completely initializes every entity during the construction of the session factory. Among many other things this includes:
A ProxyFactory for every entity (required to instantiate lazily loaded entity proxies). These are currently based on byte buddy and take some time to initialize, especially for hundreds of entities.
Several UniqueEntityLoader per entity (one per LockMode). Apart from the fact that we don’t need all lock modes, they are also expensive to initialize because they contain the SQL string required to load the entity.
This makes sense for a production environment, but during development a quicker startup time is more important because usually only a fraction of all entities is used. It therefore makes more sense to initialize these objects on the fly when they are needed for the first time.