Announcement Announcement Module
Collapse
No announcement yet.
Duplicated mBean names Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Duplicated mBean names

    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:

    Code:
    @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.
    Last edited by asarco; Apr 5th, 2007, 11:07 AM.

  • #2
    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/sp...ation-behavior

    Comment


    • #3
      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.

      Comment


      • #4
        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.

        Comment


        • #5
          Ok, done.

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

          Code:
          /**
           * 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;
              }
          
          }
          Code:
              <bean id="jmxAttributeSource" class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource"/>
              <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!

          Comment


          • #6
            ServletContextAware ObjectNamingStrategy

            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.

            Code:
            /**
             * Sample of an {@link MetadataNamingStrategy} extension to append the
             * {@link ServletContext#getServletContextName()} in the canonical name
             * 
             * @author <a href="mailto:[email protected]">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
            Last edited by Cyrille Le Clerc; May 19th, 2007, 11:48 AM. Reason: use [code] instead of [quote]

            Comment

            Working...
            X