The Spring framework minimizes architectural dependencies and materializes the components in the application, but the application is still managed. Fortunately, Spring 1.2 includes advanced JMX integration support, and JMX provides a practical management infrastructure for applications. In this article, Claude Duguay further from Spring JMX, showing you how to transparently increase notification events for methods and properties. The resulting code allows you to monitor state changes without messing with Java? Object.
While the default configuration of the Spring framework's JMX management infrastructure is good, there is still room for customization, especially when it comes to higher-level features provided by Model MBean. In this article, I used a relatively simple operation-increasing notification events for methods and properties of spring based applications-to help you familiarize yourself with the custom of spring JMX. After completing my example from beginning to end, you will be able to tailor the Spring JMX management infrastructure to your application's needs.
I'll start with a simple review of the JMX API, Spring Framework, and spring JMX, and then move on to the development extension. The first extension allows me to configure MBean metadata in an external XML format, which, like Hibernate mapping files, can be stored with Java objects in the classpath. My second extension adds a simple naming convention for the Modelmbean class to transparently configure custom notification messages. A new notification message is triggered either before or after the property changes or when a particular method is invoked.
The end of the article is a practical example based on the Mockup service object, which needs to manage its startup and stopping methods and read-write properties. I tested this implementation with a small client/server application designed specifically for this purpose. The application server is a standard Java 5.0 Mbeanserver and complements the HTTP adapters originating from the mx4j Open source project.
JMX Overview
Java Management Extensions (JMX) is a java-based standard for managing and monitoring services on your network. The core of the JMX API is the managed bean, which is
MBean。 MBean provides a facility layer for managed resources such as applications, services, and devices. In short, MBean provides a flexible, adapter-based architecture for opening properties and operations of java-based (or Java-packaged) resources. Once opened, you can use browsers and HTTP connections or monitor and manage these resources through protocols such as SMTP or SOAP.
The MBean that is written and deployed is open through the Mbeanserver interface to make the different application views interactive. Mbeanserver instances can also be combined into arbitrary federated relationships to form more complex distributed environments.
The JMX standard provides four different MBean:
- Standard Mbean implements methods for managing objects directly, either by implementing a programmer-defined interface that ends with the class name "MBean", or by using a Standard MBean instance that takes a class as a constructor parameter. Plus an optional interface class specification. This interface can be open to some of the object methods used for administration.
- Dynamic MBean uses property accessors to dynamically access properties and calls methods with a generalized invoke () method. The available methods are specified in the Mbeaninfo interface. This approach is more flexible, but does not have type security like the Standard MBean. It dramatically reduces coupling, and manageable POJO (purely old-fashioned Java objects) do not need to implement specific interfaces.
- The model MBean provides an improved abstraction layer and expands the Dynamic MBean model to further reduce the dependency on a given implementation. This can be useful for scenarios where multiple versions of the JVM may be used or where there is a need for loosely coupled management of third-party classes. The main difference between the Dynamic Mbean and the model Mbean is that there is additional metadata in the model Mbean.
- The Open MBean is a restricted Model MBean, which restricts the type to a fixed set of types for maximum portability. By restricting data types, you can use more adapters, and technologies such as SMTP can be more easily adapted to the management of Java applications. This variant also specifies standard structures such as arrays and tables to improve the management of composite objects.
If you want to control both the client and the server, then the Standard MBean is one of the easiest variants to implement. The benefits are of a type, but there is a lack of flexibility if used in a more generalized management console environment. If you plan to use a Dynamic Mbean, you can also use the Model MBean more often, and in most cases it will improve the abstraction layer with little added complexity. The open MBean is the most portable variant and is the only way to open a composite object. Unfortunately, the amount of code required to open a composite structure in an open MBean is too large to be cost-effective only if you need a high-level business management solution.
JMX also supports notification of the use of event models with filters and broadcasters. For this purpose, the Standard MBean needs to declare a mbeaninfo metadata description. Standard MBean implementations typically construct these internally, and developers cannot see them directly. Later in this article, you'll see how to use the XML descriptor format of Model MBean metadata and Spring's JMX support for a virtually transparent configuration.
Spring offers help
Like Java EE, the Spring framework provides many powerful Java development features in one architecture. Unlike Java EE, the Spring-open technology source offers a wide range of choices that are no longer dependent on the burden. For example, the object-relational mapping tool for Spring can replicate the behavior of Enterprise JavaBean without causing inflexibility. Although the EJB specification restricts this approach, Spring provides a number of technical interfaces that allow you to choose the interface that best fits your application's requirements, or create your own interfaces if needed. Similarly, use Spring's dynamic proxy classes to add transactional or security restrictions to Java objects, keeping them neat and tailored to application space rather than infrastructure requirements.
Spring's AOP-centric (IOC) bean can largely separate the infrastructure from the business objects. Therefore, crosscutting concerns, such as logs, transactions, and security, will no longer interfere with application code.
IOC (Control reversal) is the main strategy to reduce the coupling degree. Spring's IOC implementation uses dependency injection to effectively "reverse" the control from the application code to the Spring container. Spring is not about coupling classes to an application's object graph at creation time, which allows you to configure classes and their dependencies with XML or property files (although XML is considered the best method). The reference is then "injected" with a standard accessor to the object on which the class depends. It can be seen as a materialized composite (externalizing composition), which in a typical application is far more specific than inheritance.
AOP is the key to managing crosscutting concerns in application development. As implemented in traditional object-oriented programming, these concerns are handled as separate instances, potentially generating unrelated code (or confusion) in the application class. Spring uses an AOP specification and an XML configuration file to crystallize crosscutting concerns, thus preserving the purity of Java code.
Introducing Spring JMX
The JMX in Spring 1.2 supports the use of easily configurable bean proxies for automatic mbeanserver registration and supports standard JSR-160 remote connectors. In the simplest case, you can use Spring JMX to register objects with the Mbeanexporter class. Spring automatically recognizes Standardmbean or wraps objects with Modelmbean proxies, using introspection by default. You can use Beanexporter to declare beans in an explicit reference, or you can automatically detect a bean with either a default policy or a more complex policy.
The large number of assemblers provided by Spring 1.2 make it possible to transparently construct an Mbean, including the use of introspective, Standard MBean interfaces, metadata (using class-level annotations), and explicitly declared method names. Spring's model based on the exporter and assembler is easy to expand and provides the required control when creating a registered MBean.
JMX registers and accesses administrative objects using the ObjectName language. If you choose to use Autoenrollment, Spring provides a different naming strategy. When you use the key naming policy, you can use a property to associate the MBean name with the Nameobject instance. If you implement the Managedresource interface, you can use the metadata naming conventions. Because of Spring's highly flexible architecture and a large number of extension points, you can implement your own policies.
By default, Spring discovers the Mbeanserver instance that is running, and creates a default instance if no instance is running or is not explicitly declared. Directly instantiating your own mbeanserver with the Spring configuration is just as easy as using a variety of connectors. Spring provides control through client and server connections and provides client agents to assist client programming.
All of these features are provided by Spring 1.2 by default. Although Spring JMX offers a number of options, the default exporter is sufficient for many projects, allowing you to run quickly. However, when using JMX, some attributes are noted when using an implicit MBean construct. As a result, it is possible to move slowly from the Standard Mbean to the Model MBean, which allows more control over the application's properties, operations, and notification metadata. To preserve the benefits of loose coupling (that is, the intrinsic benefits of Spring's flexible architecture), you need to implement this control outside of the Java object.
Spring's IOC makes it easy to rely on externally connected (wire) objects, and it's easy to take advantage of this in the spring's architecture. IOC retains the injection of object dependencies, making it easy to add, replace, or supplement the behavior of objects, including Spring's JMX support. In the remainder of this article, I will focus on extending the Spring JMX to get more granular application management without messing up the application code or disrupting the flexibility inherent in spring.
Extending Spring JMX
The Spring framework provides a number of useful tools for dealing with JMX, including extension points for extending JMX functionality. I'll use them to gain more control over the Mbeaninfo declaration without commenting on Java objects. To do this, I'm going to extend Spring JMX in two ways: The first method can configure MBean metadata in an external XML format (similar to the JBoss microkernel), and the second method can be stored with its associated Java object in the Classpath (much like the Hibernate mapping file) 。
I'll extend the Requiredmodelmbean class so that it uses a simple naming convention to find the relevant Mbean deployment descriptor in the . Mbean.xml format. The definition of this xml-based MBean descriptor improves control over application metadata without losing the flexibility of POJO based design and Spring compositing. To achieve this, I will implement my own assembler and extend the basic Spring JMX exporter. An extended exporter can create an extended Modelmbean that supports the interception of property changes and notification of before and after methods execution. I can do all this with Spring's AOP mechanism, but Modelmbean is already the proxy for the underlying managed resource, so I'm going to extend the Requiredmodelmbean class in a more straightforward way.
Management Basics
No matter what technology you use, there are three key areas to focus on when managing resources:
- attributes (sometimes called properties, fields, or variables). Read-only properties are useful for open metrics or states. Read/write properties allow administrators to change the configuration.
- Action (executable call, which is the method for Java code). Actions are used to trigger events such as startup and shutdown, or other application-specific actions.
- Event (a notification to the monitoring system that reflects the state change or the execution of some actions). Notification confirms that the operation or state change does occur. Notifications can also be used to trigger events, such as responding to state changes that exceed the threshold of setting thresholds, such as memory or insufficient resources for disk space. This notification can be used to send an e-mail or pager to an application administrator when the system needs attention.
As I extend Spring JMX, I'll use a simple case to illustrate each of the three areas of concern: a sample service with a start and stop method and a read-write property to manage. I will also test this implementation with a small client/server application and open an HTTP management interface that uses the MX4J adapter. All examples will have the necessary limitations, but sufficient to enable you to understand the corresponding concepts. You'll see how easy it is to add JMX notification events to your Spring-based application methods and properties, and the result is that you can monitor state changes without adding unnecessary code to the Java object.
Mbeaninfo Model
If you download the code related to this article, you will find a package named Com.claudeduguay.mbeans.model that contains a set of classes for modeling mbeaninfo XML files. This package contains a large number of classes, so I'm not going to discuss all the classes in detail, but the basics still need to be explained.
The root of the model is the Mbeandescriptor class, which provides a creatembeaninfo () method that is responsible for creating a JMX-compatible Modelmbeaninfo instance with application metadata. The Mbeandescriptorutil class provides two static read () methods that load and save the XML document model. The Document and Element instances used in this model are based on the JDOM framework.
The basic Mbeaninfo correlation classes and descriptor models that I use are closely related. All the basic properties in the base class are modeled in XML and can be defined in a simple format. For example, the <mbean> tag is the root of my document. It is directly related to Modelmbeaninfo, and it expects atypeAndDescriptionProperty. The type is the fully qualified class name of the managed bean. However, when using my sping solution, this class can be completely derived from the context. The <mbean> tag expects 0 or moreattribute、Operation、ConstructorAndNotificationSub type. Each of them provides a base Mbeaninfo class XML attribute.
Figure 1. MBean XML Format
The MBean model implementation utilizes several Jdom-related tool classes in the Com.claudeduguay.util.jdom package. They are primarily the interfaces that parse and construct document and Element objects, and a tool class makes it easier to read and write the document stream. Most of the code to view is in the com.claudeduguay.mbeans.spring package.
Already done enough preparatory work, let's start to expand Spring jmx!
improve notifications in Modelmbean
The first thing I'm going to do is extend the Spring JMX Modelmbean implementation so that you can send notifications without directly implementing this behavior in managed resources. To do this, you also need to extend the Spring exporter to create an improved Modelmbean instance. Finally, a new assembler is needed to extract mbeaninfo metadata from the mapping file.
One of the purposes of the
Modelmbeanextension class
Extension Requiredmodelmbean class is to enable notifications transparently in the administrative agent. This application requires three kinds of notifications: set the property value, before the method call, and after the method call. Because the message is configured in my own way, it can provide information as I need it in every case. To do this, I used a naming convention for type notifications, where type names are delimited for style . checkpoints. The matching type must be set, before, or one of the after. If the type is set, it is considered a property name, otherwise it is considered a method name. The Modelmbean code for the
Extension uses additional classes to help with coupling. The first is Notificationinfomap, a simple Map constructed with notification metadata, associated with a prefix ( Set|before|after ) naming ( Method|attribute ) style, This allows for more efficient matching of notification metadata. The second is a static collection of tool methods. Listing 1 shows the Requiredmodelmbean extended for notifications:
Listing 1. Modelmbeanextension
Package com.claudeduguay.mbeans.spring; Import java.lang.reflect.*; Import javax.management.*; Import javax.management.modelmbean.*; public class Modelmbeanextension extends Requiredmodelmbean {protected Notificationinfomap notificationinfomap; protected Modelmbeaninfo Modelmbeaninfo; protected Object Managedbean; Public Modelmbeanextension () throws mbeanexception {} public modelmbeanextension (Modelmbeaninfo modelmbeaninfo) thro WS mbeanexception {super (modelmbeaninfo); This.modelmbeaninfo = Modelmbeaninfo; Notificationinfomap = new Notificationinfomap (modelmbeaninfo); } public void Setmodelmbeaninfo (Modelmbeaninfo modelmbeaninfo) throws Mbeanexception {This.modelmbeaninfo = Modelmbeaninfo; Notificationinfomap = new Notificationinfomap (modelmbeaninfo); Super.setmodelmbeaninfo (Modelmbeaninfo); Mbeannotificationinfo[] Getnotificationinfo () {return modelmbeaninfo.getnotifications (); } public void Setmanagedresource (Object Managedbean, String type) throws Mbeanexception, Runtimeoperationsexception, Instance Notfoundexception, invalidtargetobjecttypeexception {super.setmanagedresource (Managedbean, type); This.managedbean = Managedbean; } protected void Maybesendmethodnotification (String type, string name) throws Mbeanexception {mbeannotific Ationinfo info = notificationinfomap. Findnotificationinfo (type, name); if (info!= null) {Long timeStamp = System.currenttimemillis (); String NotificationType = Modelmbeanutil. MatchType (Info, "." + Type + "." + name); SendNotification (New Notification (NotificationType, this, TimeStamp, Info.getdescription ())); } protected void Maybesendattributenotification (attribute) throws Mbeanexception, Attributenotfou Ndexception, Invalidattributevalueexception, reflectionexception {String name = Attribute.getname (); Mbeannotificationinfo info = notificationinfomap. Findnotificationinfo ("Set", Attribute.getname ()); if (info!= null) {Object oldValue = getattribute (name); Object newvalue = Attribute.getvalue (); Long TimeStamp = System.currenttimemillis (); String NotificationType = Modelmbeanutil. MatchType (Info, ". Set." + name); SendNotification (This, TimeStamp, TimeStamp, Info.getdescription (), info, new attributechangenotification. GetName (), NotificationType, OldValue, NewValue); } public Object Invoke (String name, object[] args, string[] signature) throws Mbeanexception, Reflectio nexception {maybesendmethodnotification ("before", name); Object returnvalue = Super.invoke (name, args, signature); Maybesendmethodnotification ("after", name); Return returnvalue; Public Object getattribute (String name) throws Mbeanexception, Attributenotfoundexception, reflectionexception { try {Method method = Modelmbeanutil.findgetmethod (Modelmbeaninfo, Managedbean, name); Return Method.invoke (Managedbean, new object[] {}); catch (Illegalaccessexception e) {throw new Mbeanexception (e); catch (InvocationTargetException e) {throw new Mbeanexception (e); } public void SetAttribute (attribute) throws Mbeanexception, Attributenotfoundexception, Invalid Attributevalueexception, Reflectionexception {try {method method = Modelmbeanutil.findsetmethod ( Modelmbeaninfo, Managedbean, Attribute.getname ()); Method.invoke (Managedbean, Attribute.getvalue ()); Maybesendattributenotification (attribute); catch (InvocationTargetException e) {throw new Mbeanexception (e); catch (Illegalaccessexception e) {throw new Mbeanexception (e); } } } |
no proxy agent required!
Because Modelmbean is already an agent, you do not need to use the agent mechanism of Spring and the AOP interceptor to intercept interesting methods. The Modelmbean interface requires an implementation of the setattribute and invoke methods to manage calls to the underlying managed resources. You can inherit the Requiredmodelmbean class, make sure it appears in all JMX implementations, and increase the functionality I need.
My modelmbeanextension implements the same constructor, but stores a copy of Modelmbeaninfo in an instance variable. Because this value can be set by a constructor or by invoking the Setmodelmbeaninfo method, I override this method to store this value, calling the superclass to complete the default behavior. By default, the Requiredmodelmbean class adds two general notification descriptors, so I override the Getnotificationinfo () method and return only the notifications I describe. General notifications are still sent, but customers who require specific notifications will not see them.
To send notifications, I covered the setattribute () and Invoke () methods and checked to see if the call matched my notification information descriptor. Traversing the list every time should not incur much overhead because most classes send only a limited set of notifications, but I need to test many of the notification type strings for each notification, and repeating this process seems like a waste. To ensure that no performance problems are encountered, I instantiate a
Notification Information Mapping, which is a name/information map that can be used for quick queries. The key is a simple string with a type prefix (set, before, or after) and the properties and methods involved. You can use the Findnotificationinfo () method to find instances of notification information when setattribute () calls or method calls.
Once you have completed the infrastructure, you can intercept calls to the setattribute () and Invoke () methods. Property changes need to send a attributechangenotification instance that requires an old attribute value and a new value, as well as details that can be obtained from the notification information descriptor. When sending notifications, if the order of messages is confusing, send the sequence number so that the client application can sort the message. To simplify, I used the current timestamp instead of managing a counter. When you create a notification object, the SendNotification () method guarantees that it will be published. The same idea is used for the Invoke () method, although I use a simpler Notification object here. You can call the Invoke () method in the superclass to check both (before and after) and send before and after notifications based on the lookup results.