extending the Spring JMX exporter
To use the extended Modelmbean, you need to overwrite the Createmodelmbean () method in Spring Mbeanexporter. Because you can inject the assembler properties, you must know that it may not be the fact that I expected. You can set the required assembler in the constructor, but you need to return a normal modelmbean when the assembler changes. All you have to do is cache a mbeaninfoassembler local reference and check what type it is when you create a new Modelmbean. Listing 2 shows all of these changes:
Listing 2. Mbeandescriptorenabledexporter
Package com.claudeduguay.mbeans.spring; Import javax.management.*; Import javax.management.modelmbean.*; Import org.springframework.jmx.export.*; Import org.springframework.jmx.export.assembler.*; public class Mbeandescriptorenabledexporter extends Mbeanexporter { protected Mbeaninfoassembler Mbeaninfoassembler; Public Mbeandescriptorenabledexporter () { Setassembler (new Mbeandescriptorbasedassembler ()); } Public Modelmbean Createmodelmbean () throws Mbeanexception { if (Mbeaninfoassembler instanceof Mbeandescriptorbasedassembler) {return new modelmbeanextension (); } return Super.createmodelmbean (); } public void Setassembler (Mbeaninfoassembler mbeaninfoassembler) { This.mbeaninfoassembler = Mbeaninfoassembler; Super.setassembler (Mbeaninfoassembler); |
When using this extended class, you can change the assembler in the standard Spring language and return to the default behavior when needed. In most cases, this version is not worth using if the extension is eventually bypassed. However, if you want to use the extended Modelmbean with a new custom assembler, you can now do so.
Build a custom assembler
The main task of this custom assembler is to find metadata mapping files related to the managed classes. Once the file is found, it is loaded and the necessary Modelmbeaninfo instance is generated. To do this, I just implemented the Spring Mbeaninfoassembler instance to establish the relevant classpath for this file, with static
Mbeandescriptorutil.read ()method to load it and return the result, as shown in Listing 3:
Listing 3. Mbeandescriptorbasedassembler
Package com.claudeduguay.mbeans.spring; Import java.io.*; Import javax.management.modelmbean.*; Import org.springframework.core.io.*; Import org.springframework.jmx.export.assembler.*; Import com.claudeduguay.mbeans.model.*; public class Mbeandescriptorbasedassembler implements Mbeaninfoassembler {public Modelmbeaninfo getmbeaninfo (OBJ ECT Managedbean, String beankey) {string name = Managedbean.getclass (). GetName (); String path = Name.replace ('. ', '/') + ". Mbean.xml"; Classpathresource resource = new Classpathresource (path); InputStream input = null; try {input = Resource.getinputstream (); Mbeandescriptor descriptor = mbeandescriptorutil.read (input); return Descriptor.creatembeaninfo (); catch (Exception e) {throw new IllegalStateException ("Unable to load resource:" + path); finally {if (input!= null) {try {input.close ();} catch (Exception x) {}} } } } |
This mbeandescriptorbasedassembler ignores the bean key parameters and creates the desired Modelmbeaninfo instance directly with the managed bean reference.
Sample
In the remainder of this article, I will highlight the use of this Spring JMX extension. To do this, use a hypothetical service that opens two methods and a property, thus showing a typical use case.
Exampleservice is a Java object that, when invoked, simply outputs to the console, as shown in Listing 4:
Listing 4. Exampleservice
Package com.claudeduguay.jmx.demo.server; public class Exampleservice { protected String propertyvalue = "Default value"; Public Exampleservice () {} public String GetPropertyValue () { System.out.println ("Exampleservice:get Property Value "); return propertyvalue; } public void setPropertyValue (String propertyvalue) { System.out.println (' Exampleservice:set property Value "); This.propertyvalue = PropertyValue; } public void StartService () { System.out.println ("Exampleservice:start Service called"); } public void StopService () { System.out.println ("Exampleservice:stop Service called"); |
a friendly message to the administrator
This extended descriptor can almost directly correlate attributes and operations. The main point of a descriptor method superior to an introspective approach is that it provides more specific messages. The configuration options for the notification descriptor depend on the naming specification of the type (XML) attribute. The actual name is arbitrary, but the code is triggered by the Set.name, Before.name, and after.name styles in the type. In this case, I associate the set notification with the PropertyValue (JMX) attribute, associating the before with the after notification with the StartService () and the StopService () method. Again, these extensions allow me to make good use of descriptive messages.
In Listing 5, you can see that a property and two methods are defined. The notification descriptor defines the preceding and subsequent events of the method and a property setting notification:
Listing 5. ExampleService.mbean.xml
<?xml version= "1.0" "> <mbean name=" Exampleservice "description=" Example Service "type=" Com.claudeduguay.jmx.demo.s Erver. Exampleservice "> <attribute name=" PropertyValue description= "property Value Access" type= "java.lang.String" rea Dable= "true" writable= "true"/> <operation name= "StopService" description= "Stop Example Service"/> <operation Nam E= "StartService" description= "Start Example Service"/> <notification name= "Propertyvalueset" types= Vice.set.propertyValue "description=" PropertyValue was set "/> <notification" name= "Beforestartservice" ex Ample.service.before.startService "description=" Example service is starting "/> <notification name=" Afterstartservic E "types=" Example.service.after.startService "description=" example service is started "/> <notification name=" to be Forestopservice "types=" Example.service.before.stopService "description=" example service is stopping "/> <notifi Cation Name= "afterStopService "types=" Example.service.after.stopService "description=" example service is Stopped "/> </mbean> |
Configuring the server
To run this example in a client/server environment, you need to configure and start a Mbeanserver instance. To do this, I use the Java 5.0 Mbeanserver instance, which guarantees that I can manage my own code using the administrative extensions provided in the JVM. If you want, you can also run multiple instances of Mbeanserver, and you can try it yourself as a practice if you like.
Like Java 5.0, the Spring framework allows you to configure your own Mbeanserver instances. I chose to use Java 5.0 because it supports JSR-160 connectors, and my client code will need it.
Listing 6. Springjmxserver
Package com.claudeduguay.jmx.demo.server; Import org.springframework.context.*; Import org.springframework.context.support.*; Import mx4j.tools.adaptor.http.*; * * To use the springjmxserver with the following command line * Arguments to activate the Java 1.5 JMX server.
* * -dcom.sun.management.jmxremote.port=8999 * -dcom.sun.management.jmxremote.ssl=false * - Dcom.sun.management.jmxremote.authenticate=false */public class Springjmxserver {public static void main ( String[] args) throws Exception { String spring_file = "com/claudeduguay/jmx/demo/server/ Springjmxserver.xml "; ApplicationContext context = new Classpathxmlapplicationcontext (spring_file); Httpadaptor httpadaptor = (httpadaptor) Context.getbean ("Httpadaptor"); Httpadaptor.start (); |
Because of the mbeandescriptorenabledexporter, the Spring configuration file for the server is very simple. In addition to declaring exampleservice, I increased the mx4j required to open an HTTP adapter and connect Xsltprocessor to Httpadaptor. Note that this is a very useful area of Spring's IOC implementation. Listing 7 shows the Spring configuration file for my Springjmxserver instance:
Listing 7. Springjmxserver.xml
If you prefer (assuming you followed my settings), you can run this server now. It registers Exampleservice and runs the HTTP adapter. Do not forget to start the Java 5.0 mbeanserver using the command-line arguments mentioned in the annotation, or you will get the default instance, and the client example will not work.
Running client code
After you start the server, you can run the client code, as shown in Listing 8, to see what happens. This code implements the JMX Notificationlistener interface so that you can interactively see what's going on. Once connected, you can register the listener and then trigger several calls, start and stop services, set and get properties. In each case, you should see a notification message on the console that confirms the action.
Listing 8. Springjmxclient
Package com.claudeduguay.jmx.demo.client; Import java.util.*; Import javax.management.*; Import javax.management.remote.*; public class Springjmxclient implements Notificationlistener {public void handlenotification (Notification Notifica tion, Object handback) {System.out.println ("Notification:" + notification.getmessage ()); public static void Main (string[] args) throws Exception {springjmxclient listener = new Springjmxclient ( ); String address = "Service:jmx:rmi:///jndi/rmi://localhost:8999/jmxrmi"; Jmxserviceurl serviceurl = new Jmxserviceurl (address); MAP <String,Object> environment = NULL; Jmxconnector connector = jmxconnectorfactory.connect (serviceurl, Environment); Mbeanserverconnection mbeanconnection = Connector.getmbeanserverconnection (); ObjectName exampleservicename = objectname.getinstance ("Services:name=exampleservice"); Mbeanconnection.addnotificationlistener ( Exampleservicename, listener, NULL, NULL); Mbeanconnection.invoke (Exampleservicename, "StartService", NULL, NULL); Mbeanconnection.setattribute (Exampleservicename, New Attribute ("PropertyValue", "New value"); System.out.println (Mbeanconnection.getattribute (Exampleservicename, "propertyvalue")); Mbeanconnection.invoke (Exampleservicename, "StopService", NULL, NULL); } } |
Because HTTP adapters are also available, you can try to manage the same methods and properties using MX4J (a browser connection to port 8080). If you have the client code running at the same time, you will also see notifications for these actions.
Concluding remarks
In this article, I showed you how to extend Spring's JMX support to meet the specific needs of your application. Here, I use Spring's container based architecture and AOP framework to increase notification events for JMX methods and properties. Of course, I've only scratched the surface of Spring's JMX capability. There are many other extensions, and Spring and JMX are big themes, each worthy of further study.