3. Bootstrap

The term bootstrapping refers to initializing and starting a software component. In Hibernate, we are specifically talking about the process of building a fully functional SessionFactory instance or EntityManagerFactory instance, for JPA. The process is very different for each.

During the bootstrap process, you might want to customize Hibernate behavior so make sure you check the Configurations section as well.

3.1. Native Bootstrapping

This section discusses the process of bootstrapping a Hibernate SessionFactory. Specifically, it addresses the bootstrapping APIs as redesigned in 5.0. For a discussion of the legacy bootstrapping API, see Legacy Bootstrapping.

3.1.1. Building the ServiceRegistry

The first step in native bootstrapping is the building of a ServiceRegistry holding the services Hibernate will need during bootstrapping and at run time.

Actually, we are concerned with building 2 different ServiceRegistries. First is the org.hibernate.boot.registry.BootstrapServiceRegistry. The BootstrapServiceRegistry is intended to hold services that Hibernate needs at both bootstrap and run time. This boils down to 3 services:

org.hibernate.boot.registry.classloading.spi.ClassLoaderService

which controls how Hibernate interacts with ClassLoaders.

org.hibernate.integrator.spi.IntegratorService

which controls the management and discovery of org.hibernate.integrator.spi.Integrator instances.

org.hibernate.boot.registry.selector.spi.StrategySelector

which controls how Hibernate resolves implementations of various strategy contracts. This is a very powerful service, but a full discussion of it is beyond the scope of this guide.

If you are ok with the default behavior of Hibernate in regards to these BootstrapServiceRegistry services (which is quite often the case, especially in stand-alone environments), then you don’t need to explicitly build the BootstrapServiceRegistry.

If you wish to alter how the BootstrapServiceRegistry is built, that is controlled through the org.hibernate.boot.registry.BootstrapServiceRegistryBuilder:

Example 266. Controlling BootstrapServiceRegistry building

  1. BootstrapServiceRegistryBuilder bootstrapRegistryBuilder =
  2. new BootstrapServiceRegistryBuilder();
  3. // add a custom ClassLoader
  4. bootstrapRegistryBuilder.applyClassLoader( customClassLoader );
  5. // manually add an Integrator
  6. bootstrapRegistryBuilder.applyIntegrator( customIntegrator );
  7. BootstrapServiceRegistry bootstrapRegistry = bootstrapRegistryBuilder.build();

The services of the BootstrapServiceRegistry cannot be extended (added to) nor overridden (replaced).

The second ServiceRegistry is the org.hibernate.boot.registry.StandardServiceRegistry. You will almost always need to configure the StandardServiceRegistry, which is done through org.hibernate.boot.registry.StandardServiceRegistryBuilder:

Example 267. Building a BootstrapServiceRegistryBuilder

  1. // An example using an implicitly built BootstrapServiceRegistry
  2. StandardServiceRegistryBuilder standardRegistryBuilder =
  3. new StandardServiceRegistryBuilder();
  4. // An example using an explicitly built BootstrapServiceRegistry
  5. BootstrapServiceRegistry bootstrapRegistry =
  6. new BootstrapServiceRegistryBuilder().build();
  7. StandardServiceRegistryBuilder standardRegistryBuilder =
  8. new StandardServiceRegistryBuilder( bootstrapRegistry );

A StandardServiceRegistry is also highly configurable via the StandardServiceRegistryBuilder API. See the StandardServiceRegistryBuilder Javadocs for more details.

Some specific methods of interest:

Example 268. Configuring a MetadataSources

  1. ServiceRegistry standardRegistry =
  2. new StandardServiceRegistryBuilder().build();
  3. MetadataSources sources = new MetadataSources( standardRegistry );
  4. // alternatively, we can build the MetadataSources without passing
  5. // a service registry, in which case it will build a default
  6. // BootstrapServiceRegistry to use. But the approach shown
  7. // above is preferred
  8. // MetadataSources sources = new MetadataSources();
  9. // add a class using JPA/Hibernate annotations for mapping
  10. sources.addAnnotatedClass( MyEntity.class );
  11. // add the name of a class using JPA/Hibernate annotations for mapping.
  12. // differs from above in that accessing the Class is deferred which is
  13. // important if using runtime bytecode-enhancement
  14. sources.addAnnotatedClassName( "org.hibernate.example.Customer" );
  15. // Read package-level metadata.
  16. sources.addPackage( "hibernate.example" );
  17. // Read package-level metadata.
  18. sources.addPackage( MyEntity.class.getPackage() );
  19. // Adds the named hbm.xml resource as a source: which performs the
  20. // classpath lookup and parses the XML
  21. sources.addResource( "org/hibernate/example/Order.hbm.xml" );
  22. // Adds the named JPA orm.xml resource as a source: which performs the
  23. // classpath lookup and parses the XML
  24. sources.addResource( "org/hibernate/example/Product.orm.xml" );
  25. // Read all mapping documents from a directory tree.
  26. // Assumes that any file named *.hbm.xml is a mapping document.
  27. sources.addDirectory( new File( ".") );
  28. // Read mappings from a particular XML file
  29. sources.addFile( new File( "./mapping.xml") );
  30. // Read all mappings from a jar file.
  31. // Assumes that any file named *.hbm.xml is a mapping document.
  32. sources.addJar( new File( "./entities.jar") );
  33. // Read a mapping as an application resource using the convention that a class named foo.bar.MyEntity is
  34. // mapped by a file named foo/bar/MyEntity.hbm.xml which can be resolved as a classpath resource.
  35. sources.addClass( MyEntity.class );

3.1.2. Event Listener registration

The main use cases for an org.hibernate.integrator.spi.Integrator right now are registering event listeners and providing services (see org.hibernate.integrator.spi.ServiceContributingIntegrator). With 5.0 we plan on expanding that to allow altering the metamodel describing the mapping between object and relational models.

Example 269. Configuring an event listener

  1. public class MyIntegrator implements org.hibernate.integrator.spi.Integrator {
  2. @Override
  3. public void integrate(
  4. Metadata metadata,
  5. SessionFactoryImplementor sessionFactory,
  6. SessionFactoryServiceRegistry serviceRegistry) {
  7. // As you might expect, an EventListenerRegistry is the thing with which event
  8. // listeners are registered
  9. // It is a service so we look it up using the service registry
  10. final EventListenerRegistry eventListenerRegistry =
  11. serviceRegistry.getService( EventListenerRegistry.class );
  12. // If you wish to have custom determination and handling of "duplicate" listeners,
  13. // you would have to add an implementation of the
  14. // org.hibernate.event.service.spi.DuplicationStrategy contract like this
  15. eventListenerRegistry.addDuplicationStrategy( new CustomDuplicationStrategy() );
  16. // EventListenerRegistry defines 3 ways to register listeners:
  17. // 1) This form overrides any existing registrations with
  18. eventListenerRegistry.setListeners( EventType.AUTO_FLUSH,
  19. DefaultAutoFlushEventListener.class );
  20. // 2) This form adds the specified listener(s) to the beginning of the listener chain
  21. eventListenerRegistry.prependListeners( EventType.PERSIST,
  22. DefaultPersistEventListener.class );
  23. // 3) This form adds the specified listener(s) to the end of the listener chain
  24. eventListenerRegistry.appendListeners( EventType.MERGE,
  25. DefaultMergeEventListener.class );
  26. }
  27. @Override
  28. public void disintegrate(
  29. SessionFactoryImplementor sessionFactory,
  30. SessionFactoryServiceRegistry serviceRegistry) {
  31. }
  32. }

3.1.3. Building the Metadata

The second step in native bootstrapping is the building of an org.hibernate.boot.Metadata object containing the parsed representations of an application domain model and its mapping to a database. The first thing we obviously need to build a parsed representation is the source information to be parsed (annotated classes, hbm.xml files, orm.xml files). This is the purpose of org.hibernate.boot.MetadataSources.

MetadataSources has many other methods as well. Explore its API and Javadocs for more information. Also, all methods on MetadataSources offer fluent-style call chaining::

Example 270. Configuring a MetadataSources with method chaining

  1. ServiceRegistry standardRegistry =
  2. new StandardServiceRegistryBuilder().build();
  3. MetadataSources sources = new MetadataSources( standardRegistry )
  4. .addAnnotatedClass( MyEntity.class )
  5. .addAnnotatedClassName( "org.hibernate.example.Customer" )
  6. .addResource( "org/hibernate/example/Order.hbm.xml" )
  7. .addResource( "org/hibernate/example/Product.orm.xml" );

Once we have the sources of mapping information defined, we need to build the Metadata object. If you are ok with the default behavior in building the Metadata then you can simply call the buildMetadata method of the MetadataSources.

Notice that a ServiceRegistry can be passed at a number of points in this bootstrapping process. The suggested approach is to build a StandardServiceRegistry yourself and pass that along to the MetadataSources constructor. From there, MetadataBuilder, Metadata, SessionFactoryBuilder, and SessionFactory will all pick up that same StandardServiceRegistry.

However, if you wish to adjust the process of building Metadata from MetadataSources, you will need to use the MetadataBuilder as obtained via MetadataSources#getMetadataBuilder. MetadataBuilder allows a lot of control over the Metadata building process. See its Javadocs for full details.

Example 271. Building Metadata via MetadataBuilder

  1. ServiceRegistry standardRegistry =
  2. new StandardServiceRegistryBuilder().build();
  3. MetadataSources sources = new MetadataSources( standardRegistry );
  4. MetadataBuilder metadataBuilder = sources.getMetadataBuilder();
  5. // Use the JPA-compliant implicit naming strategy
  6. metadataBuilder.applyImplicitNamingStrategy(
  7. ImplicitNamingStrategyJpaCompliantImpl.INSTANCE );
  8. // specify the schema name to use for tables, etc when none is explicitly specified
  9. metadataBuilder.applyImplicitSchemaName( "my_default_schema" );
  10. // specify a custom Attribute Converter
  11. metadataBuilder.applyAttributeConverter( myAttributeConverter );
  12. Metadata metadata = metadataBuilder.build();

3.1.4. Building the SessionFactory

The final step in native bootstrapping is to build the SessionFactory itself. Much like discussed above, if you are ok with the default behavior of building a SessionFactory from a Metadata reference, you can simply call the buildSessionFactory method on the Metadata object.

However, if you would like to adjust that building process, you will need to use SessionFactoryBuilder as obtained via Metadata#getSessionFactoryBuilder. Again, see its Javadocs for more details.

Example 272. Native Bootstrapping - Putting it all together

  1. StandardServiceRegistry standardRegistry = new StandardServiceRegistryBuilder()
  2. .configure( "org/hibernate/example/hibernate.cfg.xml" )
  3. .build();
  4. Metadata metadata = new MetadataSources( standardRegistry )
  5. .addAnnotatedClass( MyEntity.class )
  6. .addAnnotatedClassName( "org.hibernate.example.Customer" )
  7. .addResource( "org/hibernate/example/Order.hbm.xml" )
  8. .addResource( "org/hibernate/example/Product.orm.xml" )
  9. .getMetadataBuilder()
  10. .applyImplicitNamingStrategy( ImplicitNamingStrategyJpaCompliantImpl.INSTANCE )
  11. .build();
  12. SessionFactory sessionFactory = metadata.getSessionFactoryBuilder()
  13. .applyBeanManager( getBeanManager() )
  14. .build();

The bootstrapping API is quite flexible, but in most cases it makes the most sense to think of it as a 3 step process:

  1. Build the StandardServiceRegistry

  2. Build the Metadata

  3. Use those 2 to build the SessionFactory

Example 273. Building SessionFactory via SessionFactoryBuilder

  1. StandardServiceRegistry standardRegistry = new StandardServiceRegistryBuilder()
  2. .configure( "org/hibernate/example/hibernate.cfg.xml" )
  3. .build();
  4. Metadata metadata = new MetadataSources( standardRegistry )
  5. .addAnnotatedClass( MyEntity.class )
  6. .addAnnotatedClassName( "org.hibernate.example.Customer" )
  7. .addResource( "org/hibernate/example/Order.hbm.xml" )
  8. .addResource( "org/hibernate/example/Product.orm.xml" )
  9. .getMetadataBuilder()
  10. .applyImplicitNamingStrategy( ImplicitNamingStrategyJpaCompliantImpl.INSTANCE )
  11. .build();
  12. SessionFactoryBuilder sessionFactoryBuilder = metadata.getSessionFactoryBuilder();
  13. // Supply a SessionFactory-level Interceptor
  14. sessionFactoryBuilder.applyInterceptor( new CustomSessionFactoryInterceptor() );
  15. // Add a custom observer
  16. sessionFactoryBuilder.addSessionFactoryObservers( new CustomSessionFactoryObserver() );
  17. // Apply a CDI BeanManager ( for JPA event listeners )
  18. sessionFactoryBuilder.applyBeanManager( getBeanManager() );
  19. SessionFactory sessionFactory = sessionFactoryBuilder.build();

3.2. JPA Bootstrapping

Bootstrapping Hibernate as a JPA provider can be done in a JPA-spec compliant manner or using a proprietary bootstrapping approach. The standardized approach has some limitations in certain environments, but aside from those, it is highly recommended that you use JPA-standardized bootstrapping.

3.2.1. JPA-compliant bootstrapping

In JPA, we are ultimately interested in bootstrapping a javax.persistence.EntityManagerFactory instance. The JPA specification defines two primary standardized bootstrap approaches depending on how the application intends to access the javax.persistence.EntityManager instances from an EntityManagerFactory.

It uses the terms EE and SE for these two approaches, but those terms are very misleading in this context. What the JPA spec calls EE bootstrapping implies the existence of a container (EE, OSGi, etc), who’ll manage and inject the persistence context on behalf of the application. What it calls SE bootstrapping is everything else. We will use the terms container-bootstrapping and application-bootstrapping in this guide.

For compliant container-bootstrapping, the container will build an EntityManagerFactory for each persistent-unit defined in the META-INF/persistence.xml configuration file and make that available to the application for injection via the javax.persistence.PersistenceUnit annotation or via JNDI lookup.

Example 274. Injecting the default EntityManagerFactory

  1. @PersistenceUnit
  2. private EntityManagerFactory emf;

Or, in case you have multiple Persistence Units (e.g. multiple persistence.xml configuration files), you can inject a specific EntityManagerFactory by Unit name:

Example 275. Injecting a specific EntityManagerFactory

  1. @PersistenceUnit(
  2. unitName = "CRM"
  3. )
  4. private EntityManagerFactory entityManagerFactory;

The META-INF/persistence.xml file looks as follows:

Example 276. META-INF/persistence.xml configuration file

  1. <persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
  4. http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
  5. version="2.1">
  6. <persistence-unit name="CRM">
  7. <description>
  8. Persistence unit for Hibernate User Guide
  9. </description>
  10. <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
  11. <class>org.hibernate.documentation.userguide.Document</class>
  12. <properties>
  13. <property name="javax.persistence.jdbc.driver"
  14. value="org.h2.Driver" />
  15. <property name="javax.persistence.jdbc.url"
  16. value="jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;MVCC=TRUE" />
  17. <property name="javax.persistence.jdbc.user"
  18. value="sa" />
  19. <property name="javax.persistence.jdbc.password"
  20. value="" />
  21. <property name="hibernate.show_sql"
  22. value="true" />
  23. <property name="hibernate.hbm2ddl.auto"
  24. value="update" />
  25. </properties>
  26. </persistence-unit>
  27. </persistence>

For compliant application-bootstrapping, rather than the container building the EntityManagerFactory for the application, the application builds the EntityManagerFactory itself using the javax.persistence.Persistence bootstrap class. The application creates an EntityManagerFactory by calling the createEntityManagerFactory method:

Example 277. Application bootstrapped EntityManagerFactory

  1. // Create an EMF for our CRM persistence-unit.
  2. EntityManagerFactory emf = Persistence.createEntityManagerFactory( "CRM" );

If you don’t want to provide a persistence.xml configuration file, JPA allows you to provide all the configuration options in a PersistenceUnitInfo implementation and call HibernatePersistenceProvider.html#createContainerEntityManagerFactory.

To inject the default Persistence Context, you can use the @PersistenceContext annotation.

Example 278. Inject the default EntityManager

  1. @PersistenceContext
  2. private EntityManager em;

To inject a specific Persistence Context, you can use the @PersistenceContext annotation, and you can even pass EntityManager-specific properties using the @PersistenceProperty annotation.

Example 279. Inject a configurable EntityManager

  1. @PersistenceContext(
  2. unitName = "CRM",
  3. properties = {
  4. @PersistenceProperty(
  5. name="org.hibernate.flushMode",
  6. value= "MANUAL"
  7. )
  8. }
  9. )
  10. private EntityManager entityManager;

If you would like additional details on accessing and using EntityManager instances, sections 7.6 and 7.7 of the JPA 2.1 specification cover container-managed and application-managed EntityManagers, respectively.

3.2.2. Externalizing XML mapping files

JPA offers two mapping options:

  • annotations

  • XML mappings

Although annotations are much more common, there are projects where XML mappings are preferred. You can even mix annotations and XML mappings so that you can override annotation mappings with XML configurations that can be easily changed without recompiling the project source code. This is possible because if there are two conflicting mappings, the XML mappings take precedence over its annotation counterpart.

The JPA specification requires the XML mappings to be located on the classpath:

An object/relational mapping XML file named orm.xml may be specified in the META-INF directory in the root of the persistence unit or in the META-INF directory of any jar file referenced by the persistence.xml.

Alternatively, or in addition, one or more mapping files may be referenced by the mapping-file elements of the persistence-unit element. These mapping files may be present anywhere on the classpath.

— Section 8.2.1.6.2 of the JPA 2.1 Specification

Therefore, the mapping files can reside in the application jar artifacts, or they can be stored in an external folder location with the cogitation that that location be included in the classpath.

Hibernate is more lenient in this regard so you can use any external location even outside of the application configured classpath.

Example 280. META-INF/persistence.xml configuration file for external XML mappings

  1. <persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
  4. http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
  5. version="2.1">
  6. <persistence-unit name="CRM">
  7. <description>
  8. Persistence unit for Hibernate User Guide
  9. </description>
  10. <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
  11. <mapping-file>file:///etc/opt/app/mappings/orm.xml</mapping-file>
  12. <properties>
  13. <property name="javax.persistence.jdbc.driver"
  14. value="org.h2.Driver" />
  15. <property name="javax.persistence.jdbc.url"
  16. value="jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;MVCC=TRUE" />
  17. <property name="javax.persistence.jdbc.user"
  18. value="sa" />
  19. <property name="javax.persistence.jdbc.password"
  20. value="" />
  21. <property name="hibernate.show_sql"
  22. value="true" />
  23. <property name="hibernate.hbm2ddl.auto"
  24. value="update" />
  25. </properties>
  26. </persistence-unit>
  27. </persistence>

In the persistence.xml configuration file above, the orm.xml XML file containing all JPA entity mappings is located in the /etc/opt/app/mappings/ folder.

3.2.3. Configuring the SessionFactory Metadata via the JPA bootstrap

As previously seen, the Hibernate native bootstrap mechanism allows you to customize a great variety of configurations which are passed via the Metadata object.

When using Hibernate as a JPA provider, the EntityManagerFactory is backed by a SessionFactory. For this reason, you might still want to use the Metadata object to pass various settings which cannot be supplied via the standard Hibernate configuration settings.

For this reason, you can use the MetadataBuilderContributor class as you can see in the following examples.

Example 281. Implementing a MetadataBuilderContributor

  1. public class SqlFunctionMetadataBuilderContributor
  2. implements MetadataBuilderContributor {
  3. @Override
  4. public void contribute(MetadataBuilder metadataBuilder) {
  5. metadataBuilder.applySqlFunction(
  6. "instr", new StandardSQLFunction( "instr", StandardBasicTypes.STRING )
  7. );
  8. }
  9. }

The above MetadataBuilderContributor is used to register a SqlFuction which is not defined by the currently running Hibernate Dialect, but which we need to reference in our JPQL queries.

By having access to the MetadataBuilder class that’s used by the underlying SessionFactory, the JPA bootstrap becomes just as flexible as the Hibernate native bootstrap mechanism.

You can then pass the custom MetadataBuilderContributor via the hibernate.metadata_builder_contributor configuration property as explained in the Configuration chapter.