The short answer is: you can, but you probably shouldn't. Here's why.

To be clear, here's the sort of thing I'm talking about:

CacheControlMBean mbean = new CacheControl(thingyCache);
mbeanServer.registerMBean(mbean, objectName1);
mbeanServer.registerMBean(mbean, objectName2);

This will work, and the same MBean will be accessible through both objectName1 and objectName2. So why shouldn't you do that?

From a high level point of view, the immediate counterquestion is, why would you want to? What does it mean for the same object to be both
domain:type=CacheControl,name=Thingies and
domain:type=CacheControl,name=Whatsits ? When you access the MBean, how is it supposed to know whether it is acting as the Thingy cache controller or the Whatsit cache controller?

Well, maybe Thingies and Whatsits are actually the same, but that's an implementation detail that you don't want to expose. Let's pretend we believe that and look at some lower-level reasons why you still don't want to use the same MBean for both of them.


The first thing that ought to make you hesitate before registering the same MBean twice is the MBeanRegistration interface. As a reminder,MBeanRegistration looks like this:

public interface MBeanRegistration {
    ObjectName preRegister(MBeanServer mbs, ObjectName name) throws Exception;
    void postRegister(Boolean done);
    void preDeregister() throws Exception;
    void postDeregister();

If an MBean implements this interface, then the various methods will be called over the MBean's lifecycle: the first two before and after registration, the last two before and after unregistration. This allows an MBean to know what name it has been registered under, and in what MBean Server.

But what happens if you register the same MBean with two different names? (Or in more than one MBean Server?) Then thepreRegister method will be called once for each name. The MBean had better be able to handle this.

It isn't impossible to deal with this, but it's hard. Rather than just stashing the MBeanServer andObjectName in fields, the MBean is going to need to maintain a Set<ObjectName> and maybe aSet<MBeanServer> too. The parameter to thepostRegister method indicates whether registration was successful: if it wasn't, how do we know whichObjectName to remove from the Set? ThepreDeregister and postDeregister methods don't say what ObjectName is being unregistered, so again how do we know which one to remove from theSet?

You could probably solve this problem in most cases by checking to see whether each ObjectName in the Setis still there. For postRegister(false) andpostDeregister(), you expect one of them to be missing. You'd have to be very wary of race conditions, though. And there is still no way of knowing in preDeregisterwhich ObjectName is about to be unregistered.


If an MBean wants to emit notifications, it implements the NotificationBroadcaster interface (or better,NotificationEmitter). Then, when it emits a Notification, the notification will be sent to every listener that was added using NotificationBroadcaster.addNotificationListener. But that method doesn't have a parameter to tell you whichObjectName the client thinks it's adding its listener to. So if the same MBean is acting as the Thingy cache controller and the Whatsit cache controller, then listeners for the Thingy cache controller are presumably going to get notifications where the ObjectName returned by getSource() is the Whatsit cache controller name, and/or vice versa.

A further point is that the convenient ability to specify a reference to the MBean as the notification source and have the MBean Server replace it with the ObjectName obviously doesn't work here. Relying on that source rewriting is discouraged for other reasons, so if this were the only argument against registering the same MBean more than once it wouldn't be enough.

Inter-MXBean references

In Mustang (Java SE 6), the JMX API acquires user-defined MXBeans. (A fixed set of these already exists in in Tiger.) One of the convenient features of MXBeans for developers is the ability to code inter-MXBean references. An MXBean defines a getter for another MXBean type, like this:

public interface ModuleMXBean {
    public ProductMXBean getProduct();

The MXBean mapping converts this into an attribute calledProduct of type ObjectName. When you callgetAttribute, the ProductMXBeanreference returned by getProduct() is converted into the ObjectName under which that MXBean is registered. Obviously, for this to work that MXBean cannot be registered under more than one name. In fact MXBeans refuse to be registered under more than one name in the same MBean Server for this reason.

There are many advantages to using MXBeans, so if you are coding MBeans today you should at least be thinking about migrating them to MXBeans in the future. If you register the same MBean with more than one name then you will have problems when you migrate.

So what should you do instead?

When you are tempted to register the same MBean under two different names, most often what you really want is to have the same "resource" that has two different management views. In our example, the resource is the cache, which has one view that sees it as a cache of Thingies, and another view that sees it as a cache of Whatsits. The attributes and operations of these two views might behave the same but chances are that that is more of a coincidence than a fundamental property. As the code evolves, sooner or later you'll want some attribute to be different in each one. And as we've seen, notifications must say whether they come from one or the other. If Thingies and Whatsits are secretly the same, then when the Thingy cache overflows, the Whatsit cache will also overflow. But if I've asked to receive a notification for the former, I don't want to be told about the latter.

If you already have code that is registering the same MBean twice, you may be able to make a quick fix as follows. Instead of this...

CacheControlMBean mbean = new CacheControl(thingyCache);
mbeanServer.registerMBean(mbean, objectName1);
mbeanServer.registerMBean(mbean, objectName2);

...try this...

CacheControlMBean mbean = new CacheControl(thingyCache);
Object mbean1 = new StandardMBean(mbean, CacheControlMBean.class);
Object mbean2 = new StandardMBean(mbean, CacheControlMBean.class);
mbeanServer.registerMBean(mbean1, objectName1);
mbeanServer.registerMBean(mbean2, objectName2);

But ultimately, you'll just want to make two different MBeans that reference the same underlying resource (thingyCache here)...

CacheControlMBean thingyMBean = new CacheControl(thingyCache);
CacheControlMBean whatsitMBean = new CacheControl(thingyCache);
mbeanServer.registerMBean(thingyMBean, thingyObjectName);
mbeanServer.registerMBean(whatsitMBean, whatsitObjectName);

...which accurately reflects what you mean.

Model MBeans may also come in useful here. But that's a story for another day.