Table of Contents
The OSGi service registry enables a bundle to publish objects to a shared registry, advertised via a given set of Java interfaces. Published services also have service properties associated with them in the registry.
Spring Dynamic Modules provides an osgi
namespace for Spring (see
Appendix E, Spring Dynamic Modules Schema) that can be used to export
Spring beans as OSGi services, and
to define references to services obtained via the service registry. The
namespace elements may be used nested inside another top-level namespace
(typically the Spring beans
namespace), or within the top-level
osgi
element.
The following example shows the use of the osgi
namespace within the familiar Spring beans element:
<xml version="1.0" encoding="UTF-8"?>; <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:osgi="http://www.springframework.org/schema/osgi" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd"> <osgi:service id="simpleServiceOsgi" ref="simpleService" interface="org.xyz.MyService" /> </beans>
Use Spring Framework | |
Import Spring Dynamic Modules schema and associate a prefix with its namespace ( | |
Make sure to import Spring beans schema version 2.5. | |
Use Spring Dynamic Modules elements using the declared namespace prefix (in this example |
Using the OSGi namespace as a top-level namespace, the same service would be declared as follows:
<?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns="http://www.springframework.org/schema/osgi" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <service id="simpleServiceOsgi" ref="simpleService" interface="org.xyz.MyService" /> </beans:beans>
| |
Use Spring Dynamic Modules schema as the default namespace. | |
Import Spring Framework | |
Make sure to import Spring beans schema version 2.5. | |
Use Spring Dynamic Modules elements without any prefix. |
Using the OSGi namespace as a top-level namespace is particularly convenient when following the recommendation of section 4.1 to use a dedicated configuration file for all OSGi-related declarations.
The service
element is used to define a bean
representing an exported OSGi service. At a minimum you must specify the
bean to be exported, and the service interface that
the service advertises.
For example, the declaration
<service ref="beanToPublish" interface="com.xyz.MessageService"/>
exports the bean with name beanToPublish
with
interface com.xyz.MessageService
. The published
service will have a service property with the name
org.springframework.osgi.bean.name
set to the name of
the target bean being registered (beanToPublish
in
this case).
The bean defined by the
service
element is of type
org.osgi.framework.ServiceRegistration
and is the
ServiceRegistration
object resulting from registering
the exported bean with the OSGi service registry. By giving this bean an
id you can inject a reference to the
ServiceRegistration
object into other beans if
needed. For example:
<service id="myServiceRegistration" ref="beanToPublish" interface="com.xyz.MessageService"/>
As an alternative to exporting a named bean, the bean to be
exported to the service registry may be defined as an anonymous inner
bean of the service element. Typically the top-level namespace would be
the beans
namespace when using this style:
<osgi:service interface="com.xyz.MessageService"> <bean class="SomeClass"> ... </bean> </osgi:service>
If the bean to be exported implements the
org.osgi.framework.ServiceFactory
interface then the
ServiceFactory
contract is honored as per section 5.6
of the OSGi Service Platform Core Specification. As an alternative to
implementing this OSGi API, Spring Dynamic Modules introduces a new bean
scope, the bundle
scope. When a bean with bundle
scope is exported as an OSGi service then one instance of the bean will
be created for each unique client (service importer) bundle that
obtains a reference to it through the OSGi service registry. When a
service importing bundle is stopped, the bean instance associated with
it is disposed. To declare a bean with bundle
scope
simply use the scope
attribute of the
bean
element:
<osgi:service ref="beanToBeExported" interface="com.xyz.MessageService"/> <bean id="beanToBeExported" scope="bundle" class="com.xyz.MessageServiceImpl"/>
The OSGi Service Platform Core Specification defines the term service interface to represent the specification of a service's public methods. Typically this will be a Java interface, but the specification also supports registering service objects under a class name, so the phrase service interface can be interpreted as referring to either an interface or a class.
There are several options for specifying the service
interface(s) under which the exported service is registered. The
simplest mechanism, shown above, is to use the
interface
attribute to specify a fully-qualified
interface name. To register a service under multiple interfaces the
nested interfaces
element can be used in place of
the interface
attribute.
<osgi:service ref="beanToBeExported"> <osgi:interfaces> <value>com.xyz.MessageService</value> <value>com.xyz.MarkerInterface</value> </osgi:interfaces> </osgi:service>
It is illegal to use both interface
attribute and
interfaces
element at the same time - use only one of them.
Using the auto-export
attribute you can avoid
the need to explicitly declare the service interfaces at all by analyzing the
object class hierarchy and its interfaces.
The auto-export
attribute can have one of four
values:
disabled
: the default value; no auto-detected of service
interfaces is undertaken and the interface
attribute or interfaces
element must be used
instead.
interfaces
: the service will be registered using all of the
Java interface types implemented by the bean to be exported
class-hierarchy
: the service will be registered using the
exported bean's implementation type and super-types
all-classes
: the service will be registered using the exported
bean's implementation type and super-types plus all interfaces
implemented by the bean.
auto-export
and interface(s)
option are not exclusive; both
can be used at the same time for fine grained control over the advertised interfaces if there is such
a need. However, the former option should be enough for most cases.
For example, to automatically register a bean under all of the interfaces that it supports you would declare:
<service ref="beanToBeExported" auto-export="interfaces"/>
Given the interface hierarchy:
public interface SuperInterface {} public interface SubInterface extends SuperInterface {}
then a service registered as supporting the
SubInterface
interface is not
considered a match in OSGi when a lookup is done for services
supporting the SuperInterface
interface. For this
reason it is a best practice to export all interfaces supported by the
service being registered explicitly, using either the
interfaces
element or
auto-export="interfaces"
.
As previously described, an exported service is always
registered with the service property
org.springframework.osgi.bean.name
set to the name
of the bean being exported. Additional service properties can be
specified using the nested service-properties
element. The service-properties
element contains
key-value pairs to be included in the advertised properties of the
service. The key must be a string value, and the value must be a type
recognized by OSGi Filters. See section 5.5 of the OSGi Service
Platform Core Specification for details of how property values are
matched against filter expressions.
The service-properties
element must contain
at least one nested entry
element from the Spring
beans namespace. For example:
<service ref="beanToBeExported" interface="com.xyz.MyServiceInterface"> <service-properties> <beans:entry key="myOtherKey" value="aStringValue"/> <beans:entry key="aThirdKey" value-ref="beanToExposeAsProperty"/> <service-properties> </service>
The Spring Dynamic Modules roadmap includes support for exporting properties registered in the OSGi Configuration Administration service as properties of the registered service. See this appendix for more details.
Spring will manage explicit dependencies of a service element,
ensuring for example that the bean to be exported as a service is
fully constructed and configured before exporting it. If a service has
implicit dependencies on other components (including other service
elements) that must be fully initialized before the service can be
exported, then the optional depends-on
attribute
can be used to express these dependencies.
<service ref="beanToBeExported" interface="com.xyz.MyServiceInterface" depends-on="myOtherComponent"/>
The OSGi Service Platform Core Specification (most current
version is 4.1 at time of writing) does not specify what types and
resources are visible through the context class loader when an
operation is invoked on a service obtained via the service registry.
Since some services may use libraries that make certain assumptions
about the context class loader, Spring Dynamic Modules enables you to
explicitly control the context class loader during service execution.
This is achieved using the option
context-class-loader
attribute of the service
element.
The permissible values for the
context-class-loader
attribute are
unmanaged
(the default) and
service-provider
. When the
service-provider
value is specified, Spring Dynamic
Modules ensures that the context class loader can see all of the
resources on the class path of the bundle exporting the service.
When setting context-class-loader
to service-provider
, the service object will be proxied to
handle the class loader. If the service advertises any concrete class then CGLIB library is required .
When registering a service with the service registry, you may
optionally specify a service ranking (see section 5.2.5 of the OSGi
Service Platform Core Specification). When a bundle looks up a service
in the service registry, given two or more matching services the one
with the highest ranking will be returned. The default ranking value
is zero. To explicitly specify a ranking value for the registered
service, use the optional ranking
attribute.
<service ref="beanToBeExported" interface="com.xyz.MyServiceInterface" ranking="9"/>
As a summary, the following table lists the attributes names, possible values and a short description for each of them.
Table 5.1. OSGi <service> attributes
Name | Values | Description |
---|---|---|
interface | fully qualified class name (such as java.lang.Thread ) | the fully qualified name of the class under which the object will be exported |
ref | any bean name | Reference to the named bean to be exported as a service in the service registry. |
context-class-loader | unmanaged | service-provider | Defines how the context class loader will be managed when an operation is invoked on the
exported service. The default value is unmanaged which means that no management of
the context class loader is attempted. A value of service-provider guarantees that
the context class loader will have visibility of all the resources on the class path of
bundle exporting the service. |
auto-export | disabled | interfaces | class-hierarchy | all-classes | Enables Spring to automatically manage the set of service interfaces advertised for the
service. By default this facility is disabled . A value of interfaces advertises all
of the Java interfaces supported by the exported service. A value of class-hierarchy
advertises all the Java classes in the hierarchy of the exported service. A value of
all-classes advertises all Java interfaces and classes. |
ranking | any integer value | Specify the service ranking to be used when advertising the service. Default value is 0. |
The service defined by a service
element is
registered with the OSGi service registry when the application context
is first created. It will be unregistered automatically when the
bundle is stopped and the application context is disposed.
If you need to take some action when a service is unregistered
because its dependencies are not satisfied (or when it is registered),
then you can define a listener bean using the nested
registration-listener
element.
The declaration of a registration listener must use either the
ref
attribute to refer to a top-level bean
definition, or declare an anonymous listener bean inline. For
example:
<service ref="beanToBeExported" interface="SomeInterface"> <registration-listener ref="myListener" registration-method="serviceRegistered" unregistration-method="serviceUnregistered"/> <registration-listener registration-method="register"> <bean class="SomeListenerClass"/> </registration-listener> </service>
Listener declaration referring to a top-level bean declaration. | |
Indicate the | |
Declare only a | |
Nested listener bean declaration. |
The optional registration-method
and
unregistration-method
attributes specify the names
of the methods defined on the listener bean that are to be invoked
during registration and unregistration. A registration and unregistration
callback methods must have a signature matching one of the following formats:
public void anyMethodName(ServiceType serviceInstance, Map serviceProperties);
public void anyMethodName(ServiceType serviceInstance, Dictionary serviceProperties);
where ServiceType
can be any type compatible
with the exported service interface of the service.
The register callback is invoked when the service is initially registered at startup, and whenever it is subsequently re-registered. The unregister callback is invoked during the service unregistration process, no matter the cause (such as the owning bundle stopping).
Spring-DM will use the declared ServiceType
argument type
and invoke the registration/unregistration method only when a service of a compatible type
will be registered/unregistered.
serviceProperties
represents a map holding all the properties
of the registered/unregistered service. To preserve compatibility with the OSGi specification
this argument can be cast, if needed, to a java.util.Dictionary
.
While we discourage, it is possible to implement a Spring-DM specific interface, namely
org.springframework.osgi.service.exporter.OsgiServiceRegistrationListener
which avoids the need
to declare the registration-method
and unregistration-method
.
However, by implementing OsgiServiceRegistrationListener
, your code
becomes Spring-DM aware (which goes against the POJO philosophy).
It is possible for a listener to implement OsgiServiceRegistrationListener
interface and
declare custom methods. In this case, the Spring-DM interface methods will be called first, followed by the custom methods.