If you have spring experience, you might know what MBeanRegistration interface is for.In fact, in my point of view, it acts as BeanFactoryAware interface in Spring framework. BeanFactoryAware is used for beans implemented this interface to hold a reference to a bean factory, then later it can look up collaborating beans via this beanFactory reference.
From the picture above shows, the preRegister() method requires a MBeanServer parameter,through this way, the MBean implements MBeanRegistration can hold the reference to a MBeanServer. We can even image how MBeanRegistration works with MBeanServer, when registering MBeans in a MBeanServer, if the registered MBean implements MBeanRegistration, it will invoke preRegister() method before registering MBean in MBeanServer, and invoke postRegister() method after MBean registering.
#MBean Server
public ObjectInstance registerMBean(Object object, ObjectName name)
{
...
if(object instanceof MBeanRegistration)
(MBeanRegistration).preRegister(this,name);
// do registering
boolean isSuccessful=register(object,name);
if(object instanceof MBeanRegistration)
(MBeanRegistration).postRegister(isSuccessful);
}
And preDeregister() and postDeregister() are for unregistering case.
Although MBeanRegistration often acts like a BeanFactoryAware, but its initial purpose is to carry out operations before or after MBean registering from the MBeanServer.
After examining the MBeanRegistration, let's talk about MBeanServer. First, let's review some basic functions of MBeanServer. As we saw in previous examples, we have used MBeanServer to register mbeans. Besides that, MBean Server can also handle notification listener(add or remove), get or set attributes of mbean by their object name. As the below class diagram shows:
Method | Description |
ObjectInstance registerMBean(Object object, ObjectName name) | register an object(MBean) to MBean Server by its object name |
void unregisterMBean(ObjectName name) | unregister mbean from the MBean Server by its object name |
ObjectInstance createMBean(String className, ObjectName name) | create a MBean via its classname and register it to the MBean Server |
addNotificationListener(ObjectName name, NotificationListener listener, NotificationFilter filter, Object handback) | add listener via MBean Server, in fact, MBean Server first look up the corrsponding MBean by the first parameter object name, the found MBean must be a NotificationBroadCaster, otherwise MBean server will throw an exception, then MBean server uses the found NotificationBroadCaster to add the listener. |
Object getAttribute(ObjectName name, String attribute) | get the value of attribute from the MBean which matches the object name |
void setAttribute(ObjectName name, Attribute attribute) | set the value of attribute from the MBean which matches the object name |
In addition to the basic functions metioned above, MBean Server also provides a mechanism of querying mbeans, as we know, you could easily have more than 50 or 100 mbeans residing in your application, so that is the place where mbean server querying mechanism could play.
Method | Description |
Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) | return the set of ObjectInstance objects identifying the set of MBeans by the given query |
Set<ObjectName> queryNames(ObjectName name, QueryExp query) | return the set of ObjectName objects identifying the set of MBeans by the given query |
If we want to know how to query mbeans via MBean Server, then you have to know how the query mechanism works first. The query mechanism of MBean Server actually consists of two parts: QueryExp and ValueExp.
The above picture only shows the commonly used QueryExp, QueryExp is used to work with ValueExp or combine different QueryExp in order to build complex queries.
From the picture above, we could easily infer their purposes from their name,for example, BooleanValueExp acts as the wrapper of the boolean value and the AttibuteValueExp refers to the value of the attribute of the MBean. Before we move into some concreate examples, we need to examine the parent class of QueryExp and ValueExp,QueryEval.
public abstract class QueryEval implements Serializable {
/* Serial version */
private static final long serialVersionUID = 2675899265640874796L;
private static ThreadLocal<MBeanServer> server =
new InheritableThreadLocal<MBeanServer>();
public void setMBeanServer(MBeanServer s) {
server.set(s);
}
public static MBeanServer getMBeanServer() {
return server.get();
}
}
As we saw from the code, QueryEval uses ThreadLocal to avoid multi-thread problem. You might be wondering why QueryEval holds MBean Server reference. Recall from the class diagram of QueryExp and ValueExp, you can see that we have a 'setMBeanServer()' method in QueryExp/ValueExp interface. QueryEval provides a default implementation for setMBeanServer(MBeanServer) of QueryExp and ValueExp, that's why some QueryExps or ValueExps extend from QueryEval.
But from the usage of QueryEval, I see no need for QueryExp or ValueExp to extend from QueryEval. Take AttributeValueExp for example, as we mentioned before, AttributeValueExp indicates the value of attribute of the MBean, in order to get the attribute value from the MBean, we need to get the MBean Server first. And then get the attribute value via its getAttribute(ObjectName objName,String attribute).
#AttributeValueExp
protected Object getAttribute(ObjectName name) {
try {
// Get the value from the MBeanServer
MBeanServer server = QueryEval.getMBeanServer();
return server.getAttribute(name, attr);
} catch (Exception re) {
return null;
}
}
And when we query MBeans via MBean Server, we'll first set the MBean Server, then call the QueryExp's apply() method.
#queryMBeans
for (ObjectInstance oi : list) {
boolean res = false;
MBeanServer oldServer =QueryEval.getMBeanServer();
query.setMBeanServer(server);
try {
res = query.apply(oi.getObjectName());
} catch (Exception e) {
res = false;
} finally {
query.setMBeanServer(oldServer);
}
}
In fact, we can replace the sentence 'query.setMBeanServer(server)' with the following one since query.setMBeanServer is actually QueryEval.setMBeanServer
QueryEval.setMBeanServer(server)
Therefore, there is no need for QueryExp and ValueExp to expose the setMBeanServer() method since we all know that MBeanServer for QueryExp and ValueExp is thread-related, not QueryExp-related or ValueExp-related.And setMBeanServer() method of ValueExp has been depreciated. And I think the one in QueryExp should be depreciated too, since they both can access the MBean Server via using QueryEval.getMBeanServer().
All right, now, let's take a look at how QueryExp and ValueExp work together to form a query. Assume that we have a person MBean which has two attributes, name and age. And we have more than 50 person MBeans residing in a MBean Server, now we want to find a suitable person MBean which name is 'kevin', and we can build our query as follow:
//int 4 means the operation equals
QueryExp query=new BinaryRelQueryExp(4,new AttributeValueExp("name"),new StringValueExp("kevin")
And if we want to find a suitable person MBean which name is 'kevin' and his age is greater than 23, we can build our query as below:
QueryExp nameQuery=new BinaryRelQueryExp(4,new AttributeValueExp("Name"),new StringValueExp("kevin"));
QueryExp ageQuery=new BinaryRelQueryExp(2,new AttributeValueExp("Age"),new NumericValueExp(23));
QueryExp andQuery=new AndQueryExp(nameQuery,ageQuery);
Some of the QueryExp such as AndQueryExp, OrQueryExp can combine other query expressions together to build a complex query.
In fact, you'll find that BinaryRelQueryExp or AndQueryExp can not be imported into your class since they are not public. But we can use Query class to build queries. Let's rewrite the last example with Query.
QueryExp nameQuery=Query.eq(Query.attr("Name"), Query.value("kevin"));
QueryExp ageQuery=Query.gt(Query.attr("Age"), Query.value(23));
QueryExp andQuery=Query.and(nameQuery, ageQuery);
And it's much shorter, isn't? Well, using the querying mechanism, you can retrieve specific MBeans without manually examing the contents of each to get the one you need.