Conflict with MBean name when uploading two Spring Boot applications on the same Tomcat

3

I have two applications in Spring Boot that use a common nomenclature for beans . In this case, my pool of connections to the database is managed by HikariCP.

Due to an infrastructure problem, I had to upload two of my Spring Boot projects on the same Tomcat. When I try to do this, Tomcat returns this error:

org.springframework.jmx.export.UnableToRegisterMBeanException: Unable to register MBean [com.zaxxer.hikari.HikariConfig@60a88c19] with key 'myHikariConfig'; nested exception is javax.management.InstanceAlreadyExistsException: com.zaxxer.hikari:name=myHikariConfig,type=HikariConfig
  at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:628) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE]
  at org.springframework.jmx.export.MBeanExporter.registerBeans(MBeanExporter.java:550) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE]
  at org.springframework.jmx.export.MBeanExporter.afterSingletonsInstantiated(MBeanExporter.java:432) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE]
  at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:781) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
  at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE]
  at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE]
  ... 37 frames omitidos
Caused by: javax.management.InstanceAlreadyExistsException: com.zaxxer.hikari:name=myHikariConfig,type=HikariConfig
  at com.sun.jmx.mbeanserver.Repository.addMBean(Repository.java:437) ~[na:1.8.0_151]
  at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerWithRepository(DefaultMBeanServerInterceptor.java:1898) ~[na:1.8.0_151]
  at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerDynamicMBean(DefaultMBeanServerInterceptor.java:966) ~[na:1.8.0_151]
  at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerObject(DefaultMBeanServerInterceptor.java:900) ~[na:1.8.0_151]
  at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerMBean(DefaultMBeanServerInterceptor.java:324) ~[na:1.8.0_151]
  at com.sun.jmx.mbeanserver.JmxMBeanServer.registerMBean(JmxMBeanServer.java:522) ~[na:1.8.0_151]
  at org.springframework.jmx.support.MBeanRegistrationSupport.doRegister(MBeanRegistrationSupport.java:195) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE]
  at org.springframework.jmx.export.MBeanExporter.registerBeanInstance(MBeanExporter.java:674) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE]
  at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:618) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE]
  ... 42 common frames omitted

2018-04-18 16:09:08.482  INFO 1412 --- [           main] ationConfigEmbeddedWebApplicationContext : Closing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@271c4: startup date [Wed Apr 18 16:08:51 GFT 2018]; root of context hierarchy
2018-04-18 16:09:08.482  INFO 1412 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Unregistering JMX-exposed beans on shutdown

I know I could handle renaming the beans of both projects so they do not clash, but there are several other beans that also follow the naming pattern, as well there are other applications in Spring Boot here in the company that we will occasionally need to climb (possibly) on the same Tomcat.

So, how do you isolate each application to have a sort of " namespace " of beans in Spring? If so, how?

I'm looking for an alternative that minimizes code changes.

    
asked by anonymous 18.04.2018 / 22:17

1 answer

4

Yes, it does. By configuring the JMX domain name you get a kind of "isolation" by setting a JMX domain name . You can check the spring.jmx.default-domain property in documentation . This answer in the international OS exemplifies how to handle this.

In this case, I only needed to define a different JMX domain name for each application, not having no other action . I just needed to add the following lines in my application.properties to application 1:

spring.application.name=myFirstApp
spring.jmx.default-domain=myFirstApp

And for the other application:

spring.application.name=mySecondApp
spring.jmx.default-domain=mySecondApp

In fact, we already used another variable in application.properties that used to handle the application identifier to retrieve HikariCP's tenant routing datasource , called mybootapp.appname . So in real, the change was just put the following lines in application.properties :

spring.application.name=${mybootapp.appname}
spring.jmx.default-domain=${mybootapp.appname}

So the application.properties stayed:

mybootapp.appname=myFirstApp
spring.application.name=${mybootapp.appname}
spring.jmx.default-domain=${mybootapp.appname}
mybootapp.appname=mySecondApp
spring.application.name=${mybootapp.appname}
spring.jmx.default-domain=${mybootapp.appname}

This was the least-changed alternative I found, without having to tinker with container settings.

    
18.04.2018 / 22:17