= Services and Registries
:imagesdir: images
:toc:

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.


== What is a Service?

Services provide various 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.

NOTE: All Services are expected to implement the +org.hibernate.service.Service+ "marker" interface.  Hibernate uses
this internally for some basic type safety; it defines no methods (at the moment).

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:

* +org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl+ for using a +javax.sql.DataSource+
* +org.hibernate.c3p0.internal.C3P0ConnectionProvider+ for using a C3P0 Connection pool
* etc.

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 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.


== What is a ServiceRegistry?

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 solution to swapping (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.

image::registry_hierarchy.jpg[ServiceRegistry UML]


== ServiceBinding

The association of a given Service to a given ServiceRegistry is called a binding and is represented by the
+org.hibernate.service.spi.ServiceBinding+ interface.  Furthermore, the specific contract between a ServiceBinding
and the ServiceRegistry is represented by the +org.hibernate.service.spi.ServiceBinding.ServiceLifecycleOwner+
interface.

There are 2 ways to associate a Service with a ServiceRegistry.  The Service can be directly instantiated
and then handed to the ServiceRegistry, or a ServiceInitiator can be given to the ServiceRegistry (which the
ServiceRegistry will use if and when the Service is needed).  ServiceRegistry implementations (those using the
+org.hibernate.service.internal.AbstractServiceRegistryImpl+ convenience base implementation) register bindings
through calls to the overloaded +AbstractServiceRegistryImpl#createServiceBinding+ method accepting either a Service
instance or a ServiceInitiator instance.  However, each specific ServiceRegistry type has a dedicated builder through
which its Services are typically defined and customized.


== Types of ServiceRegistries

Currently Hibernate utilizes 3 different ServiceRegistry implementations forming a hierarchy.

=== BootstrapServiceRegistry

The root ServiceRegistry is the +org.hibernate.boot.registry.BootstrapServiceRegistry+.  +BootstrapServiceRegistry+
is a specialization of +org.hibernate.service.ServiceRegistry+.  The +BootstrapServiceRegistry+ interface adds
no new behavior, it is simply a specialization for the purpose of type safety.  In normal usage, the
+BootstrapServiceRegistry+ has no parent.

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

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


==== ClassLoaderService

This service exposes the capability to interact with ClassLoaders.  The manner in which Hibernate (or any
library) should interact with ClassLoaders varies based on the runtime environment which is hosting the application.
Application servers, OSGi containers, and other modular class loading systems impose very specific class-loading
requirements.  This service is provides Hibernate an abstraction from this environmental complexity.  And just as
importantly, it does so in a centralized, swappable manner.

The specific capabilities exposed on this service include:

* Locating +java.lang.Class+ references by name.  This includes application classes as well as "integration" classes.
* Locating resources (properties files, xml files, etc) as "classpath resources"
* Interacting with +java.util.ServiceLoader+

The service role for this service is +org.hibernate.boot.registry.classloading.spi.ClassLoaderService+.


==== IntegratorService

Applications, third-party integrators and others all need to integrate with Hibernate.  Historically this used to
require something (usually the application) to coordinate registering the pieces of each integration needed on behalf
of each integration.  The +org.hibernate.integrator.spi.Integrator+ formalized this "integration SPI".  The
IntegratorService manages all known integrators.

TIP: The concept of "Integrator" is still being actively defined and developed as part of the 5.0 codebase.  Expect
changes in these SPIs; in fact those changes are already begun in the repository branch housing 5.0 development.

There are 2 ways an integrator becomes known.

. The integrator may be manually registered by calling +BootstrapServiceRegistryBuilder#with(Integrator)+
. The integrator may be discovered, leveraging the standard Java +java.util.ServiceLoader+
capability provided by the +ClassLoaderService+.  Integrators would simply define a file named
+_/META-INF/services/org.hibernate.integrator.spi.Integrator_+ and make it available on the classpath.
+java.util.ServiceLoader+ covers the format of this file in detail, but essentially it lists classes by FQN that
implement the +org.hibernate.integrator.spi.Integrator+ one per line.

The service role for this service is +org.hibernate.integrator.spi.IntegratorService+.


==== StrategySelector

Think of this as the "short naming" service.  Historically to configure Hibernate users would often need to
give FQN references to internal Hibernate classes.

For example, to tell Hibernate to use JDBC-based transactions we need to tell it to use the
+org.hibernate.engine.transaction.internal.jdbc.JdbcTransactionFactory+ class by specifying its FQN as part of the
config:

[source]
----
hibernate.transaction.factory_class=org.hibernate.engine.transaction.internal.jdbc.JdbcTransactionFactory
----

Of course this has caused lots of problems as we refactor internal code and move these classes around into different
package structures.  Enter the concept of short-naming, using a well defined and well known "short name" for the
impl class.  For example, this JdbcTransactionFactory is registered under the short name "jdbc", so:

[source]
----
hibernate.transaction.factory_class=jdbc
----

is functionally equivalent to the initial example.  Not only is the second form more concise, it is also upgrade proof.

The short name mappings in this service can be managed, even by applications and integrators which can be very
powerful.  For more information on this aspect, see:

* +BootstrapServiceRegistryBuilder#withStrategySelector+
* +BootstrapServiceRegistryBuilder#withStrategySelectors+
* +org.hibernate.boot.registry.selector.StrategyRegistrationProvider+ (via +ServiceLoader+ discovery)
* 'StrategySelector#registerStrategyImplementor` / 'StrategySelector#unRegisterStrategyImplementor`

The service role for this service is +org.hibernate.boot.registry.selector.spi.StrategySelector+.


=== StandardServiceRegistry

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:

==== ConnectionProvider/MultiTenantConnectionProvider

The Service providing Hibernate with Connections as needed.  Comes in 2 distinct (and mutually exclusive) roles:

* +org.hibernate.engine.jdbc.connections.spi.ConnectionProvider+ provides Connections in normal environments.
* +org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider+ provides (tenant-specific) Connections
in multi-tenant environments.

==== JdbcServices

+org.hibernate.engine.jdbc.spi.JdbcServices+ is an aggregator Service (a Service that aggregates other
Services) exposing unified functionality around JDBC accessibility.

==== TransactionFactory

+org.hibernate.engine.transaction.spi.TransactionFactory+ is used to tell Hibernate how to control or integrate
with transactions.


==== JtaPlatform

When using a JTA-based +TransactionFactory+, the +org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform+
Service provides Hibernate access to the JTA +TransactionManager+ and +UserTransaction+, as well handling
+Synchronization+ registration.

Here are the steps (in order of precedence) that Hibernate follows to determine the +JtaPlatform+ to use:

. Explicit setting keyed as +"hibernate.transaction.jta.platform"+ which can refer to
** a +JtaPlatform+ instance
** a +Class<? extends JtaPlatform>+ reference
** the name (see StrategySelector service) of a +JtaPlatform+ strategy
** the FQN of a +JtaPlatform+ implementation
. Discover via the +org.hibernate.engine.transaction.jta.platform.spi.JtaPlatformResolver+ Service, which by default:
** looks for +org.hibernate.engine.transaction.jta.platform.spi.JtaPlatformProvider+ implementations via +ServiceLoader+,
if one is found its reported +JtaPlatform+ is used (first wins).
** Attempts a number of well-known Class lookups for various environments.


==== RegionFactory

This is the second level cache service in terms of starting the underlying cache provider


==== SessionFactoryServiceRegistryFactory

+org.hibernate.service.spi.SessionFactoryServiceRegistryFactory+ is a service that acts as a factory for building the
third type of ServiceRegistry, +SessionFactoryServiceRegistry+ which we will discuss next.  I opted for the "factory as
service" approach because in the current design there is really not a good exposed hook-in spot for when the
+SessionFactoryServiceRegistry+ needs to be built.  This may very well change in 5.0


=== SessionFactoryServiceRegistry

+org.hibernate.service.spi.SessionFactoryServiceRegistry+ is the 3rd standard Hibernate ServiceRegistry.  Typically,
its parent registry is the +StandardServiceRegistry+.  +SessionFactoryServiceRegistry+ is designed to hold Services
which need access to the SessionFactory.  Currently that is just 3 Services.

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


==== EventListenerRegistry

+org.hibernate.event.service.spi.EventListenerRegistry+ is the big Service managed in the +SessionFactoryServiceRegistry+.
This is the Service that manages and exposes all of Hibernate's event listeners.  A major use-case for +Integrators+ is
to alter the listener registry.

If doing custom listener registration, it is important to understand the
+org.hibernate.event.service.spi.DuplicationStrategy+ and its effect on registration.  The basic idea is to tell
Hibernate:

* what makes a listener a duplicate
* how to handle duplicate registrations (error, first wins, last wins)

==== StatisticsImplementor

+org.hibernate.stat.spi.StatisticsImplementor+ is the SPI portion of the +org.hibernate.stat.Statistics+ API.  The
collector portion, if you will.


== Service lifecycle

Managing the lifecycle of services is the big role of a ServiceRegistry as a container for those services.  The overall
lifecycle of a Service is:

. <<service-initiation,initiation>>
. (optional) <<service-configuration,configuration>>
. (optional) <<service-starting,starting>>
. in use - until registry closed
. (optional) <<service-stopping,stopping>>


[[service-initiation]]
=== Initiation (creation)

A Service needs to be initiated/created.  We'll explore the details a little more when we discuss
<<serviceregistry-building>>.  But generally speaking, either

* a Service can be instantiated directly and handed to the ServiceRegistry
* A `ServiceInitiator` can be handed to the ServiceRegistry to initiate the Service on-demand.


[[service-configuration]]
=== Configuration

A Service can optionally implement the `org.hibernate.service.spi.Configurable` interface to be handed the
`java.util.Map` of configuration settings handed to Hibernate during initial bootstrapping.  `Configurable#configure`
is called after initiation but before usage


[[service-starting]]
=== Starting

A Service can optionally implement `org.hibernate.service.spi.Startable` to receive a callback just prior to
going into "in use".  Reflexively speaking, it is generally good practice for a Service needing `Startable` to also
need `Stoppable` (<<service-stopping,stopping>>).


[[service-stopping]]
=== Stopping

A Service can optionally implement `org.hibernate.service.spi.Stoppable` to receive a callback as the Service
is taken out of "in use" as part ServiceRegistry shutdown.

=== Manageable (JMX)

A Service can optionally implement `org.hibernate.service.spi.Manageable` to be made available to JMX.

NOTE: This particular feature is still under design/development


== Service Dependencies

Services sometimes depend on other services.  For example, the DataSourceConnectionProvider service implementation
usually needs access to the JndiService to perform JNDI lookups.  This has 2 implications.  First, it means that
DataSourceConnectionProvider needs access to JndiService.  Secondly it means that the JndiService musty be fully
"in use" prior to its usage from DataSourceConnectionProvider.

There are 2 ways to obtain access to dependent Services:

. Have the Service implement `org.hibernate.service.spi.ServiceRegistryAwareService`, which will inject the
ServiceRegistry into your Service.  You can then look up any Services you need access to.  The returned Services
you lookup will be fully ready for use.
. Injecting specific Services using `@org.hibernate.service.spi.InjectService`.
.. The Service role to inject is generally inferred by the type of parameter of the method to which the annotation
is attached.  If the parameter type is different from the Service role, use `InjectService#serviceRole` to name the
role explicitly.
.. By default the Service to inject is considered required (an exception will be thrown if it is not found).  If the
service to be injected is optional, use `InjectService#required=false`.


[[serviceregistry-building]]
== Building ServiceRegistry

Once built, a ServiceRegistry is generally considered immutable.  The Services themselves might accept
re-configuration, but immutability here means adding/replacing services.  So all the services hosted in a particular
ServiceRegistry must be known up-front.  To this end, building a ServiceRegistry usually employees a
https://en.wikipedia.org/wiki/Builder_pattern[builder^].

=== Building BootstrapServiceRegistry

Building the `BootstrapServiceRegistry` is normally done via the 'org.hibernate.boot.registry.BootstrapServiceRegistryBuilder`
class which exposes methods for defining `ClassLoaders`	to use, non-discoverable `Integrators` to incorporate, etc.

By default Hibernate will use the Thread-context ClassLoader (TCCL), if one, as well as the ClassLoader of its classes
as the ClassLoaders it will consult when asked to load classes or resources or to perform ServiceLoader resolutions.
You can tell Hibernate to consider any additional ClassLoaders via the overloaded
`BootstrapServiceRegistryBuilder#with(ClassLoader)` method:

[source,java]
----
BootstrapServiceRegistry bootstrapServiceRegistry = new BootstrapServiceRegistryBuilder()
        .with( anAdditionalClassLoader )
        .with( anotherAdditionalClassLoader )
        .build();
----

NOTE: you can also tell Hibernate to use a completely different ClassLoaderService implementation using
`BootstrapServiceRegistryBuilder#with(ClassLoaderService)`.

Integrators are normally discovered via the JDK `ServiceLoader` mechanism.  To tell Hibernate about an Integrator
that will not be discovered (for whatever reason) you would use the `BootstrapServiceRegistryBuilder#with(Integrator)`
method:

[source,java]
----
BootstrapServiceRegistry bootstrapServiceRegistry = new BootstrapServiceRegistryBuilder()
        .with( new MyCustomIntegrator() )
        .build();
----

`BootstrapServiceRegistryBuilder` also exposes methods to add extra strategy selections.  Let's say we developed
a custom CORBA-based TransactionFactory named CORBATransactionFactory and that we'd like to make this available via
short-naming.  One option would be to explicitly set up the short name during BootstrapServiceRegistry building:

[source,java]
----
BootstrapServiceRegistry bootstrapServiceRegistry = new BootstrapServiceRegistryBuilder()
        .withStrategySelector( TransactionFactory.class, "corba", CORBATransactionFactory.class )
        .build();
----

If we were going to distribute our CORBATransactionFactory, we might develop a
`org.hibernate.boot.registry.selector.StrategyRegistrationProvider`:

[source,java]
----
public class CORBATransactionFactoryStrategyRegistrationProvider implements StrategyRegistrationProvider {
    public Iterable<StrategyRegistration> getStrategyRegistrations() {
        return Collections.singletonList(
                (StrategyRegistration) new SimpleStrategyRegistrationImpl<TransactionFactory>(
                        TransactionFactory.class,
                        CORBATransactionFactory.class,
                        "corba"
                )
        );
    }
}
----

which we could register explicitly:

[source,java]
----
BootstrapServiceRegistry bootstrapServiceRegistry = new BootstrapServiceRegistryBuilder()
        .withStrategySelectors( new CORBATransactionFactoryStrategyRegistrationProvider() )
        .build();
----

or define for discovery by adding a `META-INF/services/org.hibernate.boot.registry.selector.StrategyRegistrationProvider`
file to our artifact naming `CORBATransactionFactoryStrategyRegistrationProvider`.

We might combine several of these at once:

[source,java]
----
BootstrapServiceRegistry bootstrapServiceRegistry = new BootstrapServiceRegistryBuilder()
        .with( anAdditionalClassLoader )
        .with( anotherAdditionalClassLoader )
        .with( new MyCustomIntegrator() )
        .withStrategySelector( ConnectionProvider.class, "custom", MyCustomConnectionProvider.class )
        .withStrategySelectors( new CORBATransactionFactoryStrategyRegistrationProvider() )
        .build();
----

=== Building StandardServiceRegistry

Building the `StandardServiceRegistry` is normally done via the
'org.hibernate.boot.registry.StandardServiceRegistryBuilder` which exposes methods for managing settings and
controlling the services hosted by the built StandardServiceRegistry.

Managing settings can be as simple as telling the builder about one or more settings directly:

[source,java]
----
StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
        .applySetting( "hibernate.hbm2ddl.auto", true )
        .applySettings( Collections.singletonMap( "hibernate.transaction.factory_class", "jdbc" ) )
        .build();
----

Or we can tell it to load settings from various files:

[source,java]
----
StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
        .configure()                                          <1>
        .configure( "com/acme/hibernate.cfg.xml" )            <2>
        .loadProperties( "com/acme/hibernate.properties" )    <3>
        .build();
----
<1> loads settings from an XML file (conforming to the Hibernate cfg.xml DTD) via a ClassLoader resource lookup for hibernate.cfg.xml
<2> loads settings from an XML file (conforming to the Hibernate cfg.xml DTD) via a ClassLoader resource lookup for com/acme/hibernate.cfg.xml
<3> loads settings from Properties via a ClassLoader resource lookup for com/acme/hibernate.properties

The other methods of interest on `StandardServiceRegistryBuilder` relate to customizing the Services to use.  We can
either pass in a Service instance to use or the ServiceInitiator to use as already discussed.  There are 2 distinct
ways to customize the Services to use:


==== Building StandardServiceRegistry - Overriding

Here the intent is to override or replace a service impl.  Many of the standard ServiceInitiators look through the
settings to determine the appropriate service to use.  Going back to an example we have used multiple times:

[source]
----
hibernate.transaction.factory_class=jdbc
----

The standard `TransactionFactoryInitiator` looks for this setting and determines what `TransactionFactory` service
implementation to use.  Let's say for whatever reason we always want it to use JdbcTransactionFactory:

[source,java]
----
StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
        .addService( TransactionFactory.class, new JdbcTransactionFactory() )
        .build();
----

Or say we want to resolve the service implementation to use differently:

[source,java]
----
StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
        .addInitiator( new MyCustomTransactionFactoryInitiator() )
        .build();
----

==== Building StandardServiceRegistry - Expanding

Here the intent is to 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 TopicPublisher.  So we will expand the ServiceRegistry to host this
completely new Service role:


[source,java]
----
/**
 * The service role
 */
public interface EventPublishingService extends Service {
    public void publish(Event theEvent);
}

/**
 * A disabled (no-op) impl
 */
public class DisabledEventPublishingServiceImpl implements EventPublishingService {
    public static DisabledEventPublishingServiceImpl INSTANCE = new DisabledEventPublishingServiceImpl();

    private DisabledEventPublishingServiceImpl() {
    }

    @Override
    public void publish(Event theEvent) {
        // nothing to do...
    }
}

/**
 * A standard impl
 */
public class EventPublishingServiceImpl
        implements EventPublishingService, Configurable, Startable, Stoppable, ServiceRegistryAwareService {

    private ServiceRegistryImplementor serviceRegistry;
    private String jmsConnectionFactoryName;
    private String destinationName;

    private Connection jmsConnection;
    private Session jmsSession;
    private MessageProducer publisher;

    @Override
    public void injectServices(ServiceRegistryImplementor serviceRegistry) {
        this.serviceRegistry = serviceRegistry;
    }

	public void configure(Map configurationValues) {
	    this.jmsConnectionFactoryName = configurationValues.get( JMS_CONNECTION_FACTORY_NAME_SETTING );
	    this.destinationName = configurationValues.get( JMS_DESTINATION_NAME_SETTING );
	}

    @Override
	public void start() {
	    final JndiService jndiService = serviceRegistry.getService( JndiService.class );
	    final ConnectionFactory jmsConnectionFactory = jndiService.locate( jmsConnectionFactoryName );

        this.jmsConnection = jmsConnectionFactory.createConnection();
        this.jmsSession = jmsConnection.createSession( true,  Session.AUTO_ACKNOWLEDGE );

	    final Destination destination = jndiService.locate( destinationName );

	    this.publisher = jmsSession.createProducer( destination );
	}

    @Override
    public void publish(Event theEvent) {
        publisher.send( theEvent );
    }

    @Override
	public void stop() {
        publisher.close();
        jmsSession.close();
        jmsConnection.close();
	}
}

public class EventPublishingServiceInitiator implements StandardServiceInitiator<EventPublishingService> {
    public static EventPublishingServiceInitiator INSTANCE = new EventPublishingServiceInitiator();
    public static final String ENABLE_PUBLISHING_SETTING = "com.acme.EventPublishingService.enabled";

	public Class<R> getServiceInitiated() {
	    return EventPublishingService.class;
	}

    @Override
	public R initiateService(Map configurationValues, ServiceRegistryImplementor registry) {
	    final boolean enabled = extractBoolean( configurationValues, ENABLE_PUBLISHING_SETTING );
	    if ( enabled ) {
	        return new EventPublishingServiceImpl();
	    }
	    else {
	        return DisabledEventPublishingServiceImpl.INSTANCE;
	    }
	}
}
----

Now, lets tell Hibernate about this custom Service:


[source,java]
----
StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
        .addInitiator( EventPublishingServiceInitiator.INSTANCE )
        ...
        .build();
----

== Conclusion

TODO