Hibernate.orgCommunity Documentation

Hibernate Integrations Guide

Hibernate - Relational Persistence for Idiomatic Java

5.1.17.Final

2018-11-28


Table of Contents

Preface
1. Get Involved
2. Getting Started Guide
1. Services and Registries
1.1. What is a Service?
1.1.1. Service contracts
1.1.2. Service dependencies
1.2. What is a ServiceRegistry?
1.3. ServiceBinding
1.4. Types of ServiceRegistries
1.4.1. BootstrapServiceRegistry
1.4.2. StandardServiceRegistry
1.4.3. SessionFactoryServiceRegistry
1.5. Custom Services
1.5.1. Custom Service Implementations (overriding)
1.5.2. Custom Service Roles (extending)

List of Examples

1.1. Custom ConnectionProvider implementation
1.2. Overriding service implementation via StandardServiceRegistryBuilder
1.3. LatestAndGreatestConnectionProviderImplContributor
1.4. META-INF/services/org.hibernate.service.spi.ServiceContributor
1.5. LatestAndGreatestConnectionProviderImplContributor
1.6. Custom service short-name
1.7. The EventPublishingService service role
1.8. The EventPublishingService implementation
1.9. An alternative EventPublishingService implementation
1.10. The EventPublishingServiceInitiator

Working with both Object-Oriented software and Relational Databases can be cumbersome and time consuming. Development costs are significantly higher due to a paradigm mismatch between how data is represented in objects versus relational databases. Hibernate is an Object/Relational Mapping solution for Java environments. The term Object/Relational Mapping refers to the technique of mapping data from an object model representation to a relational data model representation (and visa versa). See http://en.wikipedia.org/wiki/Object-relational_mapping for a good high-level discussion.

Note

While having a strong background in SQL is not required to use Hibernate, having a basic understanding of the concepts can greatly help you understand Hibernate more fully and quickly. Probably the single best background is an understanding of data modeling principles. You might want to consider these resources as a good starting point:

Hibernate not only takes care of the mapping from Java classes to database tables (and from Java data types to SQL data types), but also provides data query and retrieval facilities. It can significantly reduce development time otherwise spent with manual data handling in SQL and JDBC. Hibernate’s design goal is to relieve the developer from 95% of common data persistence-related programming tasks by eliminating the need for manual, hand-crafted data processing using SQL and JDBC. However, unlike many other persistence solutions, Hibernate does not hide the power of SQL from you and guarantees that your investment in relational technology and knowledge is as valid as always.

Hibernate may not be the best solution for data-centric applications that only use stored-procedures to implement the business logic in the database, it is most useful with object-oriented domain models and business logic in the Java-based middle-tier. However, Hibernate can certainly help you to remove or encapsulate vendor-specific SQL code and will help with the common task of result set translation from a tabular representation to a graph of objects.

Services and registries are new *as a formalized concept* starting in 4.0. But the functionality provided by the different Services have actually been around in Hibernate much, much longer. What is new is managing them, their lifecycles and dependencies through a lightweight, dedicated container we call a ServiceRegistry. The goal of this guide is to describe the design and purpose of these Services and Registries, as well as to look at details of their implementations where appropriate. It will also delve into the ways third-party integrators and applications can leverage and customize Services and Registries.

A services provides a certain types of functionality, in a pluggable manner. Specifically they are interfaces defining certain functionality and then implementations of those service contract interfaces. The interface is known as the service role; the implementation class is known as the service implementation. The pluggability comes from the fact that the service implementation adheres to contract defined by the interface of the service role and that consumers of the service program to the service role, not the implementation.

Generally speaking, users can plug in alternate implementations of all standard service roles (overriding); they can also define additional services beyond the base set of service roles (extending).

Let's look at an example to better define what a Service is. Hibernate needs to be able to access JDBC Connections to the database. The way it obtains and releases these Connections is through the ConnectionProvider service. The service is defined by the interface (service role) org.hibernate.engine.jdbc.connections.spi.ConnectionProvider which declares methods for obtaining and releasing the Connections. There are then multiple implementations of that service contract, varying in how they actually manage the Connections.

Internally Hibernate always references org.hibernate.engine.jdbc.connections.spi.ConnectionProvider rather than specific implementations in consuming the service (we will get to producing the service later when we talk about registries). Because of that fact, other ConnectionProvider service implementations could easily be plugged in.

There is nothing revolutionary here; programming to interfaces is generally accepted as good programming practice. What's interesting is the ServiceRegistry and the pluggable swapping of the different implementors.

A ServiceRegistry, at its most basic, hosts and manages Services. Its contract is defined by the org.hibernate.service.ServiceRegistry interface.

We already gave a basic overview and definition of services. But services have other interesting characteristics as well. Services have a lifecycle. They have a scope. Services might depend on other services. And they need to be produced (choose using one implementation over another). The ServiceRegistry fulfills all these needs.

In a concise definition, the ServiceRegistry acts as a inversion-of-control (IoC) container.

Note

Despite some recent revisionist history, Spring did not invent IoC nor dependency injection nor were they even the first to bring it into Java. Projects like JBoss MicroContainer and Apache Avalon pre-date Spring by many years and each did IoC and dependency injection. The concepts in ServiceRegistry are actually very similar to Apache Avalon.

Why not just use an existing IoC framework? The main reason was that this had to be as light-weight and as small of a footprint as possible. The initial design also had called for Services to be swappable at runtime, which unfortunately had to be removed due to performance problems in the proxy-based swapping-solution; the plan is to investigate alternate ways to achieve swap-ability with better performance at a later date.

A Service is associated with a ServiceRegistry. The ServiceRegistry scopes the Service. The ServiceRegistry manages the lifecycle of the Service. The ServiceRegistry handles injecting dependencies into the Service (actually both a pull and a push/injection approach are supported). ServiceRegistries are also hierarchical, meaning a ServiceRegistry can have a parent ServiceRegistry. Services in one registry can depend on and utilize services in that same registry as well as any parent registries.

Currently Hibernate utilizes 3 different ServiceRegistry implementations forming a hierarchy. Each type is a specialization for the purpose of type-safety, but they add no new functionality.

The org.hibernate.boot.registry.BootstrapServiceRegistry holds 3 service and is normally built by means of the org.hibernate.boot.registry.BootstrapServiceRegistryBuilder factory class. The builder gives type safe access to customizing these 3 Services.

Important

This registry holds services that absolutely have to be available for most things in Hibernate to work.

In normal usage, the BootstrapServiceRegistry has no parent.

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

The org.hibernate.boot.registry.StandardServiceRegistry defines the main Hibernate ServiceRegistry, building on the BootstrapServiceRegistry (BootstrapServiceRegistry is its parent). This registry is generally built using the org.hibernate.boot.registry.StandardServiceRegistryBuilder class. By default it holds most of the Services used by Hibernate. For the full list of Services typically held in the StandardServiceRegistry, see the source code of org.hibernate.service.StandardServiceInitiators. Some particular StandardServiceRegistry Services of note include:

In normal usage, the parent of the StandardServiceRegistry is the BootstrapServiceRegistry.

The services of the StandardServiceRegistry can be extended (added to) and overridden (replaced).

org.hibernate.service.spi.SessionFactoryServiceRegistry is the 3rd standard Hibernate ServiceRegistry. SessionFactoryServiceRegistry is designed to hold Services which need access to the SessionFactory.

Typically its parent registry is the StandardServiceRegistry.

Note

Integrators, as it stands in 4.x, operate on the SessionFactoryServiceRegistry...

Currently SessionFactoryServiceRegistry holds just 4 Services:

So far we have focused on the Hibernate provided services. But applications and integrations can provide their own services as well, either

  • providing a new implementation of a standard service (overriding)

  • providing a whole new service role (extending)

We discussed swappability of service implementations above. Lets look at an example in practice. For the sake of illustration, lets say that we have developed a new ConnectionProvider integrating with the wonderful new latest-and-greatest connection pooling library. Let's look at the steps necessary to make that happen.

The first step is to develop the actual integration by implementing the ConnectionProvider contract.


At this point we have a decision about how to integrate this new ConnectionProvider into Hibernate. As you might guess, there are multiple ways.

As a first option, we might just require that the code bootstrapping the StandardServiceRegistry do the integration.


A second option, if our LatestAndGreatestConnectionProviderImpl should always be used, would be to provide a org.hibernate.service.spi.ServiceContributor implementation as well to handle the integration on the users behalf.


We still need to be able to tell Hibernate to perform this integration for us. To do that we leverage Java's ServiceLoader. When building the StandardServiceRegistry, Hibernate will look for JDK service providers of type org.hibernate.service.spi.ServiceContributor and automatically integrate them. We discussed this behavior above. Here we'd define a classpath resource named META-INF/services/org.hibernate.service.spi.ServiceContributor. This file will have just a single line naming our impl.


A third option, if we simply want to make our LatestAndGreatestConnectionProviderImpl available as a configuration choice, we would again use a ServiceContributor but in a slightly different way.


That all allows the appication to pick our LatestAndGreatestConnectionProviderImpl by a short-name.


We can also have the ServiceRegistry host custom services (completely new Service roles). As an example, let's say our application publishes Hibernate events to a JMS Topic and that we want to leverage the Hibernate ServiceRegistry to host a Service representing our publishing of events. So we will expand the ServiceRegistry to host this completely new Service role for us and manage its lifecycle.




Because we have alternative implementations, it is a good idea to develop an initiator as well that can choose between them at runtime.


We could have the application register the EventPublishingServiceInitiator with the StandardServiceRegistryBuilder, but it is much nicer to write a ServiceContributor to handle this for the application.