1.1. What is a Service?
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.
1.1.1. Service
contracts
The basic requirement for a Service
is to implement the marker interface org.hibernate.service.Service
. Hibernate uses this internally for some basic type safety.
The Service
can also implement a number of optional life-cycle related contracts:
org.hibernate.service.spi.Startable
allows the Service
impl to be notified that it is being started and about to be put into use.
org.hibernate.service.spi.Stoppable
allows the Service
impl to be notified that it is being stopped and will be removed from use.
org.hibernate.service.spi.ServiceRegistryAwareService
allows the Service
to be injected with a reference to the registry that is managing it. See Service
dependencies for more details.
org.hibernate.service.spi.Manageable
marks the Service
as manageable in JMX provided the JMX integration is enabled. This feature is still incomplete.
Other
The different registry implementations also understand additional optional contracts specific to that registry. For details, see the details for each registry in What is a ServiceRegistry
?.
1.1.2. Service
dependencies
Services are allowed to declare dependencies on other services using either of two approaches.
@org.hibernate.service.spi.InjectService
Any method on the Service
implementation class accepting a single parameter and annotated with @InjectService
is considered requesting injection of another service.
By default, the type of the method parameter is expected to be the Service
role to be injected. If the parameter type is different than the Service
role, the serviceRole attribute of the @InjectService
annotation should be used to explicitly name the role.
By default, injected services are considered required, that is the start up will fail if a named dependent Service
is missing. If the Service
to be injected is optional, the required attribute of the @InjectService
annotation should be declared as false
(default is true
).
org.hibernate.service.spi.ServiceRegistryAwareService
The second approach is a pull approach where the Service
implements the optional Service
interface org.hibernate.service.spi.ServiceRegistryAwareService
which declares a single injectServices
method.
During startup, Hibernate will inject the org.hibernate.service.ServiceRegistry
itself into services which implement this interface. The Service
can then use the ServiceRegistry
reference to locate any additional services it needs.