Skip to content

Latest commit

 

History

History
387 lines (279 loc) · 15.2 KB

File metadata and controls

387 lines (279 loc) · 15.2 KB

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 Jakarta Persistence).

Tip

In this chapter, we will discuss on a number of specific configuration settings. Be sure to check out the appendices/SettingsReference.adoc section as well for documentation of each available setting.

Hibernate supports both native and standardized approaches for bootstrapping the SessionFactory / EntityManagerFactory.

Standardized Bootstrapping

Jakarta Persistence defines two standardized bootstrap approaches depending on the environment into which the application is deployed and on how the application intends to access the 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 Jakarta Persistence calls EE bootstrapping implies the existence of a container (EE, OSGi, etc.) that will 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 and application bootstrapping in this guide.

Note

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

Container Bootstrapping

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 jakarta.persistence.PersistenceUnit annotation or via JNDI lookup.

In these container environments, an EntityManager may be dependency injected via @PersistenceContext. In most cases, the lifecycle of such an injected EntityManager is managed by the container.

Consider the following META-INF/persistence.xml file:

Example 1. META-INF/persistence.xml file
link:extras/persistence.xml[role=include]

We can inject the EntityManagerFactory -

Example 2. Injecting a specific EntityManagerFactory
link:../../../../../../../hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/BootstrapTest.java[role=include]

Because there is only one <persistence-unit/> defined, we can also omit the name and inject the "default" EntityManagerFactory -

Example 3. Injecting the default EntityManagerFactory
link:../../../../../../../hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/BootstrapTest.java[role=include]

See the documentation of your container for additional details.

Application Bootstrapping

Jakarta Persistence also allows for the application itself to manage bootstrapping the EntityManagerFactory reference it needs. This is achieved through jakarta.persistence.Persistence or jakarta.persistence.PersistenceConfiguration.

The traditional way an application builds an EntityManagerFactory itself is to use jakarta.persistence.Persistence and either -

  • a peristence.xml file

  • manually passing a Map of settings

Example 4. Application bootstrapped EntityManagerFactory
link:../../../../../../../hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/BootstrapTest.java[role=include]

Jakarta Persistence 3.2 also introduced a new way for applications to build the EntityManagerFactory itself using jakarta.persistence.PersistenceConfiguration which offers a more type-safe approach.

Example 5. Using PersistenceConfiguration
link:../../../../../../../hibernate-core/src/test/java/org/hibernate/orm/test/jpa/boot/PersistenceConfigurationTests.java[role=include]

Hibernate offers an extension to jakarta.persistence.PersistenceConfiguration named org.hibernate.jpa.HibernatePersistenceConfiguration which exposes additional conveniences.

Example 6. Using HibernatePersistenceConfiguration
link:../../../../../../../hibernate-core/src/test/java/org/hibernate/orm/test/jpa/boot/PersistenceConfigurationTests.java[role=include]

Standardized Bootstrapping and Integrations

When performing standardized Jakarta Persistence bootstrapping, Hibernate still uses its native under the covers. Therefore, all extension/integration points discussed in that section are also available. It is especially useful in such cases that the integrations are discoverable as Java services.

Native Bootstrapping

Hibernate exposes its own approaches for bootstrapping a SessionFactory -

Native Bootstrapping: Simple

org.hibernate.cfg.Configuration provides a simple API for bootstrapping a Hibernate SessionFactory. It is a collection of settings and mappings, thrown together, and used to build the SessionFactory.

Note

Even simplified bootstrapping uses the builder-style approach under the covers, so the integration points discussed there are still available.

You can obtain the Configuration by instantiating it directly. You then specify mapping metadata (XML mapping documents, annotated classes) that describe your applications object model and its mapping to a SQL database.

Configuration cfg = new Configuration()
    // addResource does a classpath resource lookup
    .addResource( "Item.hbm.xml" )
    .addResource( "Bid.hbm.xml" )

    // calls addResource using "/org/hibernate/auction/User.hbm.xml"
    .addClass( org.hibernate.auction.User.class )

    // parses Address class for mapping annotations
    .addAnnotatedClass( Address.class )

    // reads package-level (package-info.class) annotations in the named package
    .addPackage( "org.hibernate.auction" )

    .setProperty( "hibernate.dialect", "org.hibernate.dialect.H2Dialect" )
    .setProperty( "hibernate.connection.datasource", "java:comp/env/jdbc/test" )
    .setProperty( "hibernate.order_updates", "true" );

There are other ways to specify Configuration information, including:

  • Place a file named hibernate.properties in a root directory of the classpath

  • Pass an instance of java.util.Properties to Configuration#setProperties

  • Via a hibernate.cfg.xml file

  • System properties using Java -Dproperty=value

Native Bootstrapping: Builder-style

Bootstrapping a SessionFactory may also be achieved using a number of builders. This approach is broken down into 3 course phases.

First, a ServiceRegistry is built, which represents the various services that will be available. An example of such a service is ConnectionProvider which Hibernate uses to obtain JDBC Connections. See Building the ServiceRegistry.

Next, a Metadata is built, which represents the application’s mapping information (entities, embeddables, generators, etc). See Building the Metadata.

And finally, the SessionFactory is built. See Building the SessionFactory.

While "more complex", these builders represents the actual process Hibernate goes through to build a SessionFactory. And more importantly, illustrate the various integration points in this bootstrap process.

Note

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.

Building the ServiceRegistry

As mentioned earlier, Hibernate needs a ServiceRegistry holding the services Hibernate will need during bootstrap and at run time.

Actually, there are 2 types of registries which are important here.

First is the org.hibernate.boot.registry.BootstrapServiceRegistry which contains 3 important 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.

Note

If you are ok with the default behavior of Hibernate in regard to these BootstrapServiceRegistry services (which is quite often the case, especially in stand-alone environments), then explicitly building the BootstrapServiceRegistry is not needed.

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

Example 7. Controlling BootstrapServiceRegistry building
link:../../../../../../../hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/BootstrapTest.java[role=include]

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

Example 8. Building a BootstrapServiceRegistryBuilder
link:../../../../../../../hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/BootstrapTest.java[role=include]

See the StandardServiceRegistryBuilder Javadocs for more details.

The main integration point in this process is org.hibernate.service.spi.ServiceContributor, usually provided as a Java service, which allows contributing custom Hibernate services.

Building the Metadata

To build the Metadata reference, we first construct a MetadataSources which allows specifying the different sources for mapping information. This mapping information might be in the form of XML, annotations or both.

Example 9. Building a MetadataSources
link:../../../../../../../hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/BootstrapTest.java[role=include]

Also, all methods on MetadataSources offer fluent-style call chaining -

Example 10. Configuring a MetadataSources with method chaining
link:../../../../../../../hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/BootstrapTest.java[role=include]

MetadataSources has many other methods as well. Explore its API and Javadocs for more information.

Once we have the sources of mapping information defined, we need to build the Metadata object.

If you have specified everything as settings, or you are ok with the default behavior, you can simply call MetadataSources#buildMetadata.

Example 11. Using MetadataSources#buildMetadata
link:../../../../../../../hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/BootstrapTest.java[role=include]

Optionally, we can obtain a MetadataBuilder from MetadataSources which can be used to configure the interpretation of the mapping information.

Example 12. Using MetadataBuilder
link:../../../../../../../hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/BootstrapTest.java[role=include]

There are a few integration points, usually provided as Java services, that hook into this part of bootstrapping -

  • org.hibernate.boot.model.TypeContributor which allows contributing custom types such as Java type descriptors, JDBC type descriptors, etc.

  • org.hibernate.boot.spi.MetadataSourcesContributor which allows access to MetadataSources to contribute additional sources.

  • org.hibernate.boot.spi.AdditionalMappingContributor which, like MetadataSourcesContributor, allows contributing additional sources.

  • org.hibernate.boot.spi.MetadataBuilderInitializer which allows for configuration of MetadataBuilder

Building the SessionFactory

Once we have Metadata, we can build the SessionFactory.

If all configuration has been done by settings, or if you are ok with the default behavior, you can simply call Metadata#buildSessionFactory.

Example 13. Using SessionFactoryBuilder
link:../../../../../../../hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/BootstrapTest.java[role=include]

Or a SessionFactoryBuilder, obtained from Metadata, may be used to configure the SessionFactory creation.

Example 14. Using SessionFactoryBuilder
link:../../../../../../../hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/BootstrapTest.java[role=include]

The main integration point here is org.hibernate.integrator.spi.Integrator, usually provided as a Java service, which allows contributing custom Hibernate services.

A common use case for Integrator, for example, is to hook in custom event listeners -

Example 15. Configuring an event listener
link:../../../../../../../hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/BootstrapTest.java[role=include]