Tag Archives: JMX

JMX and MBean Support With Spring

The context of this post is simply about how to use the Spring Framework to export your Spring-managed pojos for management and monitoring via JMX. Later I’ll post on using Hyperic, in the cloud, etc. First things first – as this is an update from a similar post of mine from ’08 or early ’09.

Let’s start by adding the spring jmx dependency, which will be something like this, depending on the repos you are using:

<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.core</artifactId>
<version>${spring.framework.version}</version>
</dependency>

Service Pojo

Now let’s set up some java classes for management. I have a business service that I want to monitor and a pojo to instrument.

@BusinessService
@ManagedResource(objectName = "bean:name=inventoryManager", description = "Inventory Service",
        log = true, logFile = "oms.log", currencyTimeLimit = 15, persistPolicy = "OnUpdate", persistPeriod = 200,
        persistLocation = "foo", persistName = "bar")
public class InventoryServiceImpl implements InventoryService {

    @Autowired private InventoryDao inventoryDao;

    @ManagedOperation(description = "Add two numbers")
    @ManagedOperationParameters({
            @ManagedOperationParameter(name = "x", description = "The first number"),
            @ManagedOperationParameter(name = "y", description = "The second number")})
    public int add(int x, int y) {
        return x + y;
    }

    @ManagedOperation(description = "Get inventory levels")
    @ManagedOperationParameters({@ManagedOperationParameter(name = "product", description = "The Product)})
    public long getInventoryLevel(Product product) {
        return getInventoryLevel(product.getSkew());
    }
}

First, let’s peak into my @BusinessService annotation in case you are wondering:

@Transactional
@Service
@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface BusinessService {
}

Annotating any of my service layer pojo’s makes them both transactional and with an instance created in the Spring context.

Entity Pojo

Now here is a simple pojo as an entity or javabean, what have you:

@ManagedResource(objectName = "bean:name=myPojoEntity", description = "My Managed Bean", log = true,
        logFile = "oms.log", currencyTimeLimit = 15, persistPolicy = "OnUpdate", persistPeriod = 200,
        persistLocation = "foo", persistName = "bar")
public class MyPojo {

    private long somethingToTuneInRuntime;

    /* Creates a writeable attribute for managing */
    @ManagedAttribute(description = "Tunable In Runtime Attribute",
            currencyTimeLimit = 20,
            defaultValue = "bar",
            persistPolicy = "OnUpdate")
    public void setSomethingToTuneInRuntime(long value) {
        this.somethingToTuneInRuntime = value;
    }

    @ManagedAttribute(defaultValue = "foo", persistPeriod = 300)
    public String getSomethingToTuneInRuntime() {
        return somethingToTuneInRuntime;
    }
}

Spring Config

Now let’s configure Spring to autoregister our pojos to export and manage/monitor:
Create a jmx-context.xml file in your WEB-INF/* dir

Add: <context:mbean-export/>

Activates default exporting of MBeans by detecting standard MBeans in the Spring
context as well as @ManagedResource annotations on Spring-defined beans.
Rather than defining an MBeanExporter bean, just provide this single element. I could walk you through a simple, simpler and simplest config of spring jmx but with annotational config in the simplest requirements, this is all you need to do to get up and running. If you need object naming in multiple vm situations, you can easily do that and other things too but, that’s out of scope for this post ;)

Share/Save

JMS ActiveMQ Broker Topologies and High-Availability Configuration

Pure Master Slave BrokerTopology
Pure Master Slave Simplified Topology
I am not actually going to go into Broker topologies, there are many great resources for that such as this by Bruce Snyder: http://www.slideshare.net/bruce.snyder/messaging-with-activemq-presentation or http://activemq.apache.org/topologies.html, all great stuff. This example uses a store and forward topology, or, distributed queues, and incorporates basic authentication:

My use case was to handle down JMS Servers. What I needed to do was implement failover as well as master slave strategies and a topology for message redundancy in case of hardware failure, etc. The client could not have any message loss. With failover, you can see how ActiveMQ switches from the main broker to the second, third, etc on failure. I have a case of four JMS servers in production, each server it is on is load balanced.

There are just a few configurations to add or modify in order to set up JMS Failover with Master/Slave for your broker topology. Here is a basic configuration. For this use case, all JMS servers are configured as standalone versus embedded.

I. Client URI

You will need to add the Failover protocol, either with a basic URI pattern or a composite. In this use case, there are load balanced servers in Production and multiple Development and QA environments which require different configurations for master/slave and failover.

In your application’s properties file for messaging add a modified version of this with your mappings:
activemq.broker.uri=failover://(tcp://localhost:61616,tcp://slaveh2:61616,tcp://master2:61616,tcp://slave2:61616,network:static://(tcp://localhost:61616,tcp://master2:61616,tcp://slave2:61616))?randomize=false

Note: I set connections as locked down (static) communication configurations vs multicast or dynamic discovery so that I know exactly what servers can communicate with each other and how. Also this is assuming you have one set per environment to account for mapping the appropriate IP’s in development, qa, production, dr, etc.

Note: Do not configure networkConnections for master slave, they are handled on the slave with the following configuration:
<masterConnector remoteURI= "tcp://masterhost:61616" userName="wooty" password="woo"/>

II. Spring Configuration

<bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory"
destroy-method="stop">
<property name="connectionFactory">
<bean class="org.apache.activemq.spring.ActiveMQConnectionFactory">
<constructor-arg value="${amq.broker.uri}"/>
<property name="userName" value="${activemq.username}"/>
<property name="password" value="${activemq.password}"/>
</bean>
</property
</bean>

III. Broker Configuration

Master

<broker brokerName="{hostname}" waitForSlave="true" xmlns="http://activemq.apache.org/schema/core" dataDirectory="${activemq.base}/data">
<networkConnectors>
<!-- passed in by the client broker URI so you can easily manager per environment: sweet -->
</networkConnectors>

<transportConnectors>
<!-- TCP uses the OpenWire marshaling protocol to convert messages to stream of bytes (and back) -->
<transportConnector name="tcp" uri="tcp://localhost:61616?trace=true" />
<transportConnector name="nio" uri="nio://localhost:61618?trace=true" />
<!-- <transportConnector name="ssl" uri="ssl://localhost:61617"/>
<transportConnector name="http" uri="http://localhost:61613"/
<transportConnector name="https" uri="https://localhost:61222"/> -->
<transportConnectors>
</transportConnectors>

<!-- Basic security and credentials -->
<plugins>
<simpleAuthenticationPlugin>
<users>
<authenticationUser username="system" password="manager" groups="admin, publishers,consumers"/>
</users>
</simpleAuthenticationPlugin>
</plugins>

..more configuration
</broker>

Slave: for ActiveMQ 4.1 or later which also allows for authentication as show below

<broker brokerName="{hostname}Slave" deleteAllMessagesOnStartup="true" xmlns="http://activemq.apache.org/schema/core">
<transportConnectors>
<transportConnector uri="tcp://localhost:61616"/>
</transportConnectors>

<services>
<masterConnector remoteURI= "tcp://masterhost:62001" userName="wooty" password="woo"/
</services>
<!-- Basic security and credentials -->
<plugins>
<simpleAuthenticationPlugin>
<users>
<authenticationUser username="system" password="manager" groups="admin, publishers,consumers"/>
</users>
</simpleAuthenticationPlugin>
</plugins>

</broker>

Share/Save

JMX MBean Proxying for Export via Remoting to the Client

I wanted to expose mbeans related to application monitoring and services such as a JMS broker, users in session, etc and remote that data to the client which in my case was Flex.  First I checked out using annotations for automated registration and mbean creation but that wouldn’t help me export to a remoting format..without creating my own classes. Something for another post, but what I did was create a package with some classes, which I will explain here. You can certainly deliver this strategy more minimally but I’ve found that to come back and bite me later so I’ve added in some type safety to the proxy creation of the MBeans.

The Basic Components

There are a few important components you need to set this up as a framework

1. An MBeanConnection

2. A type-safe proxy generator

3. An applicable JMX service URL, Port, Hostname

To export mbeans to the client

1. ObjectName that can be connected to if they are services

2. Ports for those services where applicable (i.e. a broker)

3. Interfaces to proxy

I. The Goal: export mbean data by remoting to the client

I created a service which is mirrored as a Flex actionscript class for remoting which encapsulates the calls for various system monitoring data via jmx: This I registered for remoting in the framework of choice, in my case it was Flex. I have a custom annotation that handles this which I don’t include in this snippet.

public class ClientMBeanService implements IClientMBeanService { ..view the code… }

II. The Delegate

With the idea of each component to be exported create a Delegate class that implements the interface dictating the contract that it must implement a method to provide the port, the ObjectName and export the mbean:

public class BrokerDelegate implements IMBeanDelegate { ..view the code… }

All Delegates must implement

public interface IMBeanDelegate { ..view the code… }

III. For Remote and Local MBeanConnections

public class MBeanConnection { ..view the code… }

IV. The Cool Part: Get a Typesafe Proxy Intance of The MBean

public final class MBeanProxyInstance { ..view the code… }

V. Typesafing: I did not originally write this class, only modified it for Java 6, but the crux is:

public class TypeSafeMBeanProxy { ..view the code… }

Share/Save