JBoss.org Community Documentation
Service POJOs allow you to define POJOs as JBoss services. The way you define them is very similar to how you define stateless or stateful session beans. One very important difference is that there will only ever be ONE instance of the service bean. i.e. it is not pooled - the bean instance is a singleton. The singleton bean contains shared state, so data set by one client is accessible by other clients.
Take a look at org.jboss.tutorial.service.bean.ServiceOne.java
.
It has been annotated with @org.jboss.ejb3.annotation.Service
, this defines it as a
singleton service in JBoss. It implements org.jboss.tutorial.service.bean.ServiceOneRemote
and org.jboss.tutorial.service.bean.ServiceOneLocal
just as you would do for a normal stateful/stateless bean.
ServiceOne also implements org.jboss.tutorial.service.bean.ServiceOneManagement
.
org.jboss.tutorial.service.bean.ServiceOne
has been annotated with @org.jboss.ejb3.annotation.Management
.
JBoss will inspect this interface, and create and install an MBean implementing the attributes and operations defined in the @Management
interface. The MBean will work on the same singleton bean instance as the remote and local interfaces.
Just as for "normal" MBeans in JBoss, the @Service
supports lifecycle management. Lifecycle management
consists of two things:
org.jboss.tutorial.service.bean.ServiceOneManagement
contains the four methods:
void create() throws Exception; void start() throws Exception; void stop(); void destroy();
You do not need to include all these methods, you can pick and choose. If present, the service container will call these methods as follows:
create
: called by the server when the service is created and all the services it depends
upon have been created too. At this point the service (and all the services it depends on) is installed in the
JMX server, but is not yet fully functional.
start
: called by the server when the service is started and all the services it depends upon
have been started too. At this point the service (and all the services it depends on) is fully functional.
stop
: called by the server when the service is stopped. At this point the service
(and all the services that depend on it) is no longer fully operational.
destroy
: called by the server when the service is destroyed and removed from the MBean server.
At this point the service (and all the services that depend on it) are destroyed.
Let's take a look at how to define the dependencies between services. Open org.jboss.tutorial.service.bean.ServiceTwo
.
Again it has been annotated with @Service, and it implements the @Management annotated interface org.jboss.tutorial.service.bean.ServiceTwoManagement
.
@Service(objectName = ServiceTwo.OBJECT_NAME) @Management(ServiceTwoManagement.class) @Depends(ServiceOne.OBJECT_NAME) public class ServiceTwo implements ServiceTwoManagement { ...
The @org.jboss.ejb3.annotation.Depends
annotation specifies that this service depends on
the service created for ServiceOne. i.e. it cannot be started until the service created for ServiceOne has been started.
You can specify an array of ObjectName
s if you depended on more than one service.
You will also notice the use of objectName
property of @Service. This is used to install the service
under a custom ObjectName instead of the default ObjectName. So in this tutorial, our ServiceTwo will be registered at
tutorial:service=ServiceTwo
Take a look at org.jboss.tutorial.bean.ServiceThree
. It has dependencies on other MBeans, but rather than
annotating the class with @Depends, the dependencies are specified on fields and setter methods.
@Depends(ServiceOne.OBJECT_NAME) public ObjectName serviceOneName; private ServiceTwoManagement service2; @Depends(ServiceTwo.OBJECT_NAME) public void setServiceTwo(ServiceTwoManagement service2) { this.service2 = service2; }
With regard to the lifecycle dependencies, the effect of annotating fields and setters with @Depends is the same
as if we annotated the class. So, ServiceThree cannot be started until ServiceOne (tutorial:service=ServiceOne
) and ServiceTwo(tutorial:service=ServiceTwo
)
are started. Annotating the fields and setters with @Depends though, allows you to inject the dependencies. So in this tutorial,
the ServiceThree.serviceOneName
will be injected with the ObjectName
which corresponds to
ServiceOne. More interesting is the injection of ServiceTwo. setServiceTwo()
takes a parameter, which is the
ServiceTwoManagement
management interface of ServiceTwo. The server creates a dynamic proxy for
the ServiceTwoManagement interface, and injects that. This means that you can call the methods on the service2
field without caring that you are actually invoking methods on another service.
You can define interceptors for your service beans in the same way as shown in the "interceptors" tutorial. This example defines one in the ServiceThree bean class itself:
@AroundInvoke public Object intercept(InvocationContext ctx) throws Exception { System.out.println("ServiceThree - Interceptor"); return ctx.proceed(); }
You can deploy a Service bean as an XMBean, where the management attributes and operations are defined via xml.
Take a look at org.jboss.tutorial.service.bean.XMBeanService
. Note the @Service annotation
specifies an xmbean
property. Also note there is no @Management annotation.
@Service(objectName = XMBeanService.OBJECT_NAME, xmbean = "resource:META-INF/service-xmbean.xml") @Remote(XMBeanServiceRemote.class) public class XMBeanService implements XMBeanServiceRemote { ...
Now take a look at META-INF/service-xmbean.xml
. This is the file referenced by the xmbean
property and specifies the bean's management attributes and operations. Note the class
, constructor
,
attribute
and operation
elements.
To build and run the example, make sure you have installed JBoss 5.x. See the Section 1.1, “JBoss Application Server 5.x” for details.
From the command prompt, move to the "service" folder under the Section 1.3, “Set the EJB3_TUTORIAL_HOME”
Make sure the "default" server configuration of JBossAS-5.x is running
$ ant $ ant run run: [java] invoking remote business interface of ServiceOne... [java] Set the attribute value through ServiceOneRemote to 100 [java] attribute value for (ServiceOne) singleton obtained via JMX is what we set via remote interface: 100 [java] Invoking ServiceThree via JMX... [java] Hello from service One [java] ServiceThree - Calling ServiceTwo.sayHello() via MBean proxy [java] invoking XMBean (configured through deployment descriptor)... [java] Set the attribute value to 50 [java] Invoking XMBean through JMX [java] attribute value for (XMBeanService deployment descriptor configured) singleton obtained via JMX is what we set via remote interface: 50 [java] Hello from an XMBean
$ mvn clean install -PRunSingleTutorial
On the server side when the application is deployed, you will notice these logs:
16:56:54,036 INFO [STDOUT] ServiceOne - Created ... 16:56:54,082 INFO [STDOUT] ServiceOne - Started ... 16:56:54,142 INFO [STDOUT] ServiceTwo - Started ... 16:56:54,226 INFO [STDOUT] ServiceThree - Started
Notice that the order is maintained because of the dependencies we have configured on the @Service.