Chapter 9. Jolokia JMX

The main focus of Jolokia is to allow easy access to JMX MBeans from everywhere. MBeans can be provided by the JVM itself, by an application server or an application itself, where each MBean is registered at a specific MBeanServer. Multiple MBeanServers can co-exist in a single JVM. The so called PlatformMBeanServer is always present and is created by the JVM during startup. Especially application servers often create additional MBeanServers for various purposes. When accessing an MBean remotely via JSR-160, the MBeanServer holding the requested MBean must be known before. Jolokia instead merges all MBeanServers it can find to give a single view on all MBeans. The merging algorithm is described in Section 9.1.1, “MBeanServer merging”.

For application specific MBeans, Jolokia provides an own, so called Jolokia MBeanServer which is treated specially by the Jolokia agent. The Jolokia MBeanServer and its features are explained in Section 9.1, “Jolokia MBeanServer”.

Developing application specific MBeans is easy, especially if Standard MBeans are used. However, for Spring users there is even a easier, more declarative way for turning POJOs into MBeans. On top of this Jolokia provides an easy, declarative way for firing up a Jolokia JVM agent merely by including some Jolokia specific Spring configuration. This is described in Section 9.3, “Spring Support”.

9.1. Jolokia MBeanServer

The Jolokia MBeanServer can be easily created and used with a locator:

MBeanServer jolokiaServer = JolokiaMBeanServerUtil.getJolokiaMBeanServer();

This server is treated specially by a Jolokia Agent:

  • Every MBean registered at the Jolokia MBeanServer will never show up remotely via JSR-160. The Jolokia MBeanServer is never exposed over JSR-160.
  • Each Jolokia MBeanServer registered MBean will shadow any MBean with the same ObjectName in any other MBeanServer present. See below for more details.
  • The Jolokia MBeanServer is also responsible for managing so called JSON MBeans. These are MBeans annotated with @JsonMBean on the class level. JSON MBean are explained in Section 9.2, “@JsonMBean”

9.1.1. MBeanServer merging

Jolokia tries hard to detect as many MBeanServer as available in a JVM. Beside the always present PlatformMBeanServer many application servers create own MBeanServer which not always can be found with standard mechanisms. Therefore Jolokia comes with so called ServerDetectors for many known brands of applications server. These server detectors know how to find MBeanServer by application server specific means.

The set of available of MBeanServers is detected during startup and kept, except for the Jolokia MBeanServer which can kick in and out at any time. For Jolokia operations, all these MBeanServers are tried according the order given below.

  • The Jolokia MBeanServer is queried first, if available.
  • Next every MBeanServer as detected by the server detectors a queried in turn.
  • All MBeanServers returned by MBeanServerFactory.findMBeanServer(null) are called if not already tried previously.
  • Finally, the ManagementFactory.getPlatformMBeanServer() is used (also, if not found in a former step).

All MBeans contained in all detected MBeanServers are merged to give a single view on the set of available MBeans. For MBeans registered with the same name at different MBeanServers, MBeans registered in later MBeanServers are not visible. These hidden MBeans will never be called on READ, WRITE or EXEC operations. Also, for LIST operations only the meta data of the visible MBeans is returned.

This hiding mechanism is used by @JsonMBean to provide a different view of an MBean for JSR-160 connectors (see below).

9.2. @JsonMBean

JMX 1.4 introduced MXBeans which allows for nearly arbitrary data to be translated into so called OpenData which are accessible via JMX. For example, arbitrary Java Beans are translated into a CompositeData structure with property names as keys and their values in OpenData values.

Jolokia provides an annotation @JsonMBean for marking an MBean as a JSON MBean. Such an MBean, if registered at the Jolokia MBeanServer creates a proxy on the PlatformMBeanServer where every complex value gets translated into plain strings in JSON format. This is true for attributes, operation return values and arguments. That way, a JSR-160 based console (like jconsole) can easily access complex data type exposed by custom MBeans. Json MBeans work for Java 6 and newer.

Figure 9.1. A JsonMBean in jconsole

A JsonMBean in jconsole

JsonMBean and MXBean are quite similar as both do a translation from complex data types to a standard format (OpenType for MXBeans, JSON strings for JsonMBean). However, there are also differences:

  • MXBeans are a standard mechanism which are available on every JVM since 1.5.[13]
  • Serialisation of complex Java Beans is more powerful with JsonMBeans, e.g. Jolokia can detect self (or cyclic) object references. MXBeans will cause an error in this case.
  • JsonMBeans must be added to the Jolokia MBeanServer to work. MXBeans work with the PlatformMBeanServer, too.
  • JsonMBean work also with JMX support libraries which use ModelMBeans unde the hood. E.g. Spring JMX uses a ModelMBean for @ManagedResource annotated MBeans. @JsonMBean can be easily added, whereas @MXBean wouldn't work here.

The Jolokia MBeanServer and the @JsonMBean annotation are contained in the Maven module jolokia-jmx.

9.3. Spring Support

A Jolokia agent can be easily integrated into a Spring application context. A dedicated artifact jolokia-spring can be used, which comes with a custom Spring configuration syntax.

For Maven based projects, a simple dependency declaration is sufficient:

<dependency>
  <groupId>org.jolokia</groupId>
  <artifactId>jolokia-spring</artifactId>
  <version>1.1.0</version>
</dependency>    

9.3.1. JVM agent

With this in place, the following configuration can be used to fire up a Jolokia JVM based agent using the HTTP server which comes with OpenJDK/Oracle JVMs (Version 6 or later).

<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:jolokia="http://www.jolokia.org/jolokia-spring/schema/config"
        xsi:schemaLocation="
       http://www.springframework.org/schema/beans 
             http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.jolokia.org/jolokia-spring/schema/config 
             http://www.jolokia.org/jolokia-spring/schema/config/jolokia-config.xsd
       ">

  <jolokia:agent lookupConfig="false" systemPropertiesMode="never">
    <jolokia:config
            autoStart="true"
            host="0.0.0.0"
            port="8778"
            ....
            />
  </jolokia:agent>
</beans>

There are two directives available: <jolokia:agent> declares a Jolokia server with a configuration as defined in an embedded <jolokia:config> configuration section.

<jolokia:agent> has an attribute lookupConfig. If set to true, externally defined <jolokia:config> sections will be looked up, too and merged with the embedded configuration. A <jolokia:config> has an order attribute, which determines the config merge order: The higher order configs will be merged later and hence will override conflicting parameters. By default, external config lookup is disabled.

The attribute systemPropertiesMode determines, how system properties with a prefix jolokia. can be used as configuration values. There are three modes available:

Table 9.1. System properties modes

Mode Description
never No lookup is done on system properties as all. This is the default mode.
fallback System properties with a prefix jolokia. are used as fallback configuration values if not specified locally in the Spring application context. E.g. jolokia.port=8888 will change the port on which the agent is listening to 8888 if the port is not explicitly specified in the configuration.
override System properties with a prefix jolokia. are used as configuration values even if they are specified locally in the Spring application context. E.g. jolokia.port=8888 will change the port on which the agent is listening to 8888 in any case.

<jolokia:config> takes as attributes all the configuration parameters for the JVM agent as described in Table 3.6, “JVM agent configuration options”. In addition, the is an extra attribute autoStart which allows for automatically starting the HTTP server during the initialization of the application context. By default this is set to true, so the server starts up automatically by default.

Just in case you don't want to use the Jolokia Spring namespace you can also use plain beans to configure a JVM agent. The following examples shows the example above with only base Spring bean configurations (including an Spring EL expression) :

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans
             http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
             http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/util
             http://www.springframework.org/schema/util/spring-util.xsd">

  <bean name="server" id="jolokia" class="org.jolokia.jvmagent.spring.SpringJolokiaAgent">
    <property name="lookupConfig" value="false"/>
    <property name="systemPropertiesMode" value="never"/>
    <property name="config">
      <bean class="org.jolokia.jvmagent.spring.SpringJolokiaConfigHolder">
        <property name="config">
          <util:map>
            <entry key="autoStart" value="true"/>
            <entry key="host" value="0.0.0.0"/>
            <entry key="port" value="#{configuration['jmx.jolokiaPort']}"/>
            ...
          </util:map>
        </property>
      </bean>
    </property>
  </bean>

</beans>

This style however is only recommended if there are some issues with the Jolokia spring configuration setup (like using Spring EL expressions in Jolokia versions earlier than 1.2.4). Otherwise, the Jolokia configuration namespace is much easier to read.

9.3.2. Jolokia MBeanServer

With <jolokia:mbean-server> the Jolokia MBeanServer can be specified. This is especially useful for adding it to <context:mbean-export> so that this MBeanServer is used for registering @ManagedResource and @JsonMBean. Remember, MBean registered at the Jolokia MBeanServer never will show up in an JSR-160 client except when annotated with @JsonMBean.

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:jolokia="http://www.jolokia.org/jolokia-spring/schema/config"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans
             http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.jolokia.org/jolokia-spring/schema/config
             http://www.jolokia.org/jolokia-spring/schema/config/jolokia-config.xsd
       http://www.springframework.org/schema/context
             http://www.springframework.org/schema/context/spring-context.xsd
       ">

  <context:mbean-export server="jolokiaServer"/>
  <jolokia:mbean-server id="jolokiaServer"/>

</beans>

9.3.3. Jolokia Spring plugin

There is an even simpler way to startup a Jolokia JVM agent with a default setup if you use a variant of the jolokia-spring module with the classifier plugin. This artefact contains a predefined Spring configuration for starting up Jolokia with default values automatically:

<dependency>
  <groupId>org.jolokia</groupId>
  <artifactId>jolokia-spring</artifactId>
  <classifier>plugin</classifier>
  <version>1.1.0</version>
</dependency>    

Beside putting this jar into the classpath (along with its dependencies) the only requirement is, that the Spring application context needs to pickup classpath:META-INF/spring/jolokia.xml. Luckily, many Spring based containers like the Camel Maven Plugin do this automatically for you, nothing has to be configured here. Otherwise this application context path has to be added manually, but in this case it is probably easier to use the non-plugin version (without classifier) and declare the Jolokia server explicitly in an existing Spring configuration file as described above.

By default, the Jolokia agent starts on port 8778 on every IP-Address of the host without security.

The configuration can be tweaked via system properties as described in Table 9.1, “System properties modes”. I.e. the plugin doesn't specify any configuration on its own and uses a systemPropertiesMode of "fallback".

As an alternative, the default settings can be customized by providing a standalone <jolokia:config> somewhere in the Spring application context. An order attribute can be used if multiple config declarations are present: the higher the order, the higher the priority. But then again, instead of using the plugin with an external configuration it is probably better to us an explicite <jolokia:agent> declaration, since you have to add to a Spring configuration file anyway.



[13] For JBoss prior to version 7 there are some slight issues since JBoss used to replace the standard MBeanServer with an own variant. See this discussion for details.