PDA

View Full Version : Duplicated mBean names



asarco
Apr 5th, 2007, 11:03 AM
Hi,

My app is composed of two WARs that run in the same Tomcat instance. I have configured some of my beans to be exposed as mBeans, they're being auto detected using annotations and they work fine.

The problem is there are some beans that are common to both webapplications, so when the second webapp starts, it fails with an exception because is trying to register some beans that are already registered, due to the class being annotated with the same name:


@ManagedResource(objectName="bean:name=pollerConfigurator", description="Poller Configurator")
public class XXXPollerConfigurator implements PollerConfigurator {Is there anything I can do? For example, using different prefixes for the names on each webapp through the Spring configuration?
I know I could not use annotations and then name every bean in each Spring configuration, but since using it with annotations is so easy, I would prefer to stick to them if possible.

Thanks,
Alex.

Mark Fisher
Apr 5th, 2007, 11:12 AM
You can control the registration behavior to either fail, ignore, or replace an existing MBean of the same name. It is documented here: http://static.springframework.org/spring/docs/2.0.x/reference/jmx.html#jmx-exporting-registration-behavior

asarco
Apr 5th, 2007, 12:00 PM
Mark, thanks for the answer.
Yes, that would prevent my second webapp from failing to start, but what I'd really want is to be able to export and manage both instances of the mBean (one from each webapp).
I will take a look at the ObjectNamingStrategy documentation to see if I can find anything there.


Alex.

Mark Fisher
Apr 5th, 2007, 12:29 PM
Yes, if you do want multiple beans to register, then investigating options for the ObjectNamingStrategy is the right path. For example, the 'IdentityNamingStrategy' would allow for that. However, if you want more meaningful names, then you might want to implement your own.

asarco
Apr 5th, 2007, 01:10 PM
Ok, done.

I've extended MetadataNamingStrategy to replace the domain part of the bean with my own supplied domain name:



/**
* Extends Spring's MetadataNamingStrategy to allow different names to different instances of the same
* bean when used inside the same container, but on different webapps.
* @author alex.sarco
*
*/
public class DomainMetadataNamingStrategy extends MetadataNamingStrategy {

private String domain;

/**
* Overrides Spring's method to replace the domain name on the objectName with the domain injected here from Spring config.
* Assumes the domain in the bean annotation is 'bean'.
*/
@Override
public ObjectName getObjectName(Object managedBean, String beanKey) throws MalformedObjectNameException {
ObjectName objectName = super.getObjectName(managedBean, beanKey);
String newName = objectName.getCanonicalName().replaceFirst("bean", domain);
return ObjectNameManager.getInstance(newName);
}

public void setDomain(String domain) {
this.domain = domain;
}

}
<bean id="jmxAttributeSource" class="org.springframework.jmx.export.annotation.Annotati onJmxAttributeSource"/>
<bean id="namingStrategy" class="xxx.xxxx.services.jmx.DomainMetadataNamingStrategy">
<property name="attributeSource" ref="jmxAttributeSource"/>
<property name="domain" value="XxxAdmin" />
</bean>Works like a charm!

Thanks for your help, Mark!

Cyrille Le Clerc
May 18th, 2007, 08:00 AM
Hello Alex,

Here is another approach relying on the name of the web application. This name is typically unique in a Tomcat server and thus is a good discriminator to prevent ObjectName collision between web apps.

I had a good experience using this discriminator in large Websphere ND topologies.



/**
* Sample of an {@link MetadataNamingStrategy} extension to append the
* {@link ServletContext#getServletContextName()} in the canonical name
*
* @author <a href="mailto:cyrille.leclerc@pobox.com">Cyrille Le Clerc</a>
*/
public class ServletContextAwareMetadataNamingStrategy extends MetadataNamingStrategy implements ServletContextAware {

protected String servletContextName;

/**
* <p>
* Overrides {@link MetadataNamingStrategy} method to append the
* {@link ServletContext#getServletContextName()} as key "application" to
* the objectName
* </p>
*
* @return objectName build with Spring metadata and the Servlet Context
* Name
*/
@Override
public ObjectName getObjectName(Object managedBean, String beanKey) throws MalformedObjectNameException {
ObjectName objectName = super.getObjectName(managedBean, beanKey);
String canonicalName = objectName.getCanonicalName();
canonicalName += ",application=" + ObjectName.quote(servletContextName) + ",bean=" + ObjectName.quote(beanKey);
ObjectName result = ObjectNameManager.getInstance(canonicalName);
return result;
}

@Override
public void setServletContext(ServletContext servletContext) {
servletContextName = servletContext.getServletContextName();
}

@Override
public String toString() {
return new ToStringCreator(this).append("servletContextName", this.servletContextName).toString();
}
}
Hope this helps,

Cyrille