Last time I wrote about JBoss, it was a discussion on how to create a JBoss service component (SAR). However, in many cases, a SAR component has to be integrated with other component-based technologies. In this article, I will discuss how to accomplish this by integrating the JBoss with the Spring component model and how to expose Spring components to receive management services from within JBoss JMX Console.
Integration
The architecture and implementation of the JBoss service component system differ vastly from the Spring Framework's component model. JBoss (version 4.x and below) implements its internal kernel, for its component container, completely on the Java Management Extension API. As such, when you build a JBoss components, you automatically inherits all the management facilities exposed by JMX. The Spring container, on the other hand, is designed to be a lightweight and portable container and has the ability to host POJO's as components. Therefore, Spring has become the container of choice for many system designers because of its simplicity and portability to be hosted in any environment.
Why would I want to integrate Spring and JBoss you ask? Well, there is an application domain that is not suited to be implemented as web-based apps. Inevitably, at some point in your career, you will need to implement headless services that expose functionalities without a GUI. These type of services are temporally durable and operate without any human intervention. When creating these types of GUI-less services, you may decide to use the Spring container as your core operating environment for POJO components. Since Spring exposes a uniform abstraction layer for the Enterprise Java API's, it makes sense to code around Spring so that your implementation is portable to any environment that can host enterprise services (JBoss container, ServiceMix, Mule, EJB's, etc). Then, your Spring components can leverage services offered by that enterprise environment (database, timers, messaging, adapters, management, etc).
Integration Points
The portability and programmability of the Spring container makes it an attractive platform for developers to create POJO component-driven apps. For web-based apps, Spring provides ready-made adapters to easily integrate your Spring context within the servlet container. However, for non-web system, Spring does not readily provide specific hooks for integration (this is a good thing, it keeps things simple). On the other hand, the Spring API exposes a simple API that makes programming the integration, of Spring in your environment, a seamless effort.
The Spring Directory Scanner
Extending on the example presented in the previous blog on JBoss components, this example demonstrates how to create a Spring-based directory scanner that gets hosted within the JBoss application container. The previous example, all of the logic of the scanner was implemented directly into the JBoss service component. While there's nothing wrong with that approach, it tightly couples your code with JBoss and make it far less portable. In this version of the scanner, the logic is encapsulated in POJO's hosted within a Spring context.
The Code
The code itself is simple and self explanatory. The JBoss service component responds to JBoss application server's life cycle events. These events are used to manage the creation and management of the Spring context. The Directory Scanner Spring component is driven by a Timer Task object mounted in Spring. Every time the timer expires, it executes the scan() method on the Directory Scanner instance.
The JBoss Service Spring Adapter
The JBoss service component is a a plain Java class with life cycle methods named create, destroy, start, stop. It implements a management interface which exposes these methods for JMX control. The component deployer will automatically execute methods create() then start() upon instantiation of the service component.
public interface JBossSpringAdapterMBean { |
Besides the life cycle methods, there are other management methods that are added for convenience. For instance, there's a method that returns the error count or one that returns the list components loaded in the spring context.
During the deployment of the JBoss Spring adapter (implemented as JBoss service component), the create(), destroy(), and start() methods of the adapter will be invoked by the JBoss service archive deployer. This provides an opportunity to instantiate and manage the Spring context at key points during the lifetime of the adapter.
Booting Spring
The create() method is called after all the setters are injected with values from the JBoss service descriptor.
public class JBossSpringAdapter implements JBossSpringAdapterMBean { |
The create() method is used to instantiate the Spring context. In the code snippet, the path to the Spring context is injected during deployment from the deployment descriptor using the setSpringConfigPath() method. The registerShutdownHook() method registers Spring to listens to VM shutdown signal so the context can properly deactivate all of its registered components.
Shutting Down the Context
On the other hand, when your JBoss adapter class receives a shutdown signal (say, the server is shutting down for instance), you wan to have your Spring context gracefully go down as well. By providing a destroy() method, the JBoss deployer invoke that method when the server sends out a shutdown signal.
public void destroy() { |
Controlling the Spring Context
Another desirable aspect of the adapter is the ability to control the Spring context with a start / stop functionality. While it is not a necessary, it affords a runtime convenience where the Spring context can be controlled and managed from a JMX console.
... |
The JBoss Service Component Descriptor
The last part of creating the JBoss Spring Adapter, is to create a JBoss Service Descriptor file (jboss-service.xml). Using this file, you can inject runtime values, and point to a descriptive xmbean descriptor file that is used to export your service archive component as an JMX MBean.
| <?xml version="1.0" encoding="UTF-8"?> <server> <mbean code="integration.jboss.JBossSpringAdapter" name="demo.integration:name=JBossSpringAdapter,type=Adapter" xmbean-dd="META-INF/spring-adapter-xmbean.xml"> <attribute name="SpringConfigPath">/META-INF/spring.xml</attribute> </mbean> </server> |
For details about creating a JBoss service component and how to format jboss-service.xml and the Xmbean descriptor file, visit the JBoss 4 User Guide.
Deploying the JBoss Spring Service Adapter
Without going into the implementation of the Spring Directory Scanner component, let's see what happens when the JBoss service archive is deployed. We expect the JBoss SAR deployer to recognize our JBoss Spring Adapter component as a valid JBoss service archive component and deploy it. Once deployed, we can validate the deployment through the log and through the JMX Console.
JBoss SAR Starting
JBoss JMX Console shows the JBoss service component JMX management interface.
The Directory Scanner Spring Component
The scanner is a simple Java object which uses the standard java.io.File package to get filtered list of files in a given directory. You will notice that there are some annotations around the class. These are Spring-specific annotations used to expose the Directory Scanner class as a managed JMX MBean (this is not covered in this writeup). I also introduce an interface called Controllable for good form (not necessary).
The Controllable Interface
public interface Controllable { |
This interface shows control points that can be implemented in the Directory Scanner. This is not necessary, but added for completion.
The Directory Scanner Class
The class that implements the logic for scanning the directory is divided into three distinct sections
- The properties (getter/setters) for the component
- The life cycle control methods
- The scanning method which is invoked to do a sweep of a a directory
@ManagedResource(description="Directory Scanner Component.", |
As you can see, this is a simple class. The thing to notice is the Spring-specific annotations that decorate the class. They are used to export and describe the class as a JMX MBean server. It's beyond the scope of this write up to go into the details of how to do this in Spring. However the next section shows the Spring file that describes and wire it all together.
The Spring Configuration File
The configuration of this component is simple and straight forward.
<bean id="scanner" class="component.spring.DirectoryScanner" init-method="start" destroy-method="stop"> |
<bean id="timerFactory" |
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter"> |
Download Source
You can download the application sample application to get the code source.
Observations
- Think in Component - component-based development is incredibly easy to get into and understand. It facilitates the separation of concerns and promotes forces you into better coding practices (testing, loose coupling, re-usability, etc).
- JBoss Service Component Evolving - Starting with version 4.x, JBoss components can now be annoted (instead of using the descriptor file) to describe its meta characteristics for JMX. Starting with version 5, JBoss will switch to OSGi as the executable unit for its components.
- Exception Management - When deploying components into a container (such as JBoss app server), great care must be taken to handle exceptions properly. In JBoss (version 4.x), when a component throws an unhandled exception, that component is immediately disabled and shutdown. You must catch all exceptions and handle them properly. In DirectoryScanner, for instance, if the scan() method throws an exception during a scanning request, the entire component is deactivated.
- (OSGi) Components Are Here to Stay - All major containers including JBoss AS, SpringSource App Platform, IBM WebSphere, Glassfish, and JOnAs support OSGi bundles as their coarse component model.
Refereces
- Source for Directory Scanner - http://vladimirvivien.com.s3.amazonaws.com/jBoss-spring-integration.zip
- JBoss Server Microkernel - http://docs.jboss.org/jbossas/jboss4guide/r4/html/ch2.chapter.html
- Spring Documentation - http://static.springframework.org/spring/docs/2.5.x/reference/index.html
- Spring JMX Documentation - http://static.springframework.org/spring/docs/2.5.x/reference/jmx.html
- OSGi - http://en.wikipedia.org/wiki/OSGi
- OSGi and Spring - http://www.infoq.com/interviews/osgi-adrian-colyer
