The same JMX Mbean class for many applications on the same server

I have over 5 spring web applications and they all use a different shared library. This shared library has its own MBeans. Due to the mandatory single objectName restriction, my applications could not be deployed on the same server.

The way I use MBeans is as follows:

@ManagedResource(objectName = "com.org.city:name=City", description = "City related operations") 

I would like to use the same MBean class with different object names for all applications. What is the correct way to use it without duplicating my MBeans.

thanks

+4
source share
5 answers

I implemented ObjectNamingStrategy for custom behavior.

  @Override public ObjectName getObjectName(Object managedBean, String beanKey) throws MalformedObjectNameException { Class managedClass = AopUtils.getTargetClass(managedBean); Hashtable<String, String> properties = new Hashtable<String, String>(); properties.put("type",ClassUtils.getPackageName(managedClass).concat(".").concat(ClassUtils.getShortName(managedClass))); properties.put("name", beanKey); return ObjectNameManager.getInstance(domain, properties); } 
+4
source

I ran into the same problem and designed a Cemo solution . Here is an example implementation.

context.xml

 <!-- Set up jmx bean auto scanning --> <!-- Note: we're not using <context:mbean-export /> because we need to provide our own naming strategy --> <bean id="mbeanExporter" class="org.springframework.jmx.export.annotation.AnnotationMBeanExporter"> <property name="namingStrategy"> <bean class="com.foo.MultiAppMetadataNamingStrategy"> <property name="applicationName" value="${application.name}" /> </bean> </property> </bean> 

MultiAppMetadataNamingStrategy.java

 public class MultiAppMetadataNamingStrategy implements ObjectNamingStrategy, InitializingBean { private String applicationName; public MultiAppMetadataNamingStrategy() { } public MultiAppMetadataNamingStrategy(String applicationName) { this.applicationName = Preconditions.checkNotNull(applicationName, "applicationName must not be null"); } public void setApplicationName(String applicationName) { this.applicationName = Preconditions.checkNotNull(applicationName, "applicationName must not be null"); } @Override public void afterPropertiesSet() throws Exception { if (applicationName == null) { throw new IllegalArgumentException("Property 'applicationName' is required"); } } @Override public ObjectName getObjectName(Object managedBean, String beanKey) throws MalformedObjectNameException { Class managedClass = AopUtils.getTargetClass(managedBean); String domain = ClassUtils.getPackageName(managedClass); Hashtable<String, String> properties = new Hashtable<>(); properties.put("type", ClassUtils.getShortName(managedClass)); properties.put("name", beanKey); // ensure the application name is included as a property in the object name properties.put("app", applicationName); return ObjectNameManager.getInstance(domain, properties); } } 

This allows you to configure mbean as:

 package com.foo; @ManagedResource(description = "Bean description") public class MyBean { ... } 

which will register mbean with the object name com.foo:name=myBean,type=MyBean,app=CustomAppName

+4
source

You need to change to register the mbean exporter behavior:

 <property name="registrationBehaviorName" value="REGISTRATION_REPLACE_EXISTING"/> 

But it still means that only one application registers a bean. And you cannot logically have more than one mbean with the same name from multiple applications. How will it be determined which application to invoke? Use the application name as a prefix for the mbean name.

0
source

You can define a simple property-based naming strategy with the owner of the place (s).
Every war will have it: own copy of app.properties
For instance.

With properties file: app.properties

 appName=MyApp1 #Every app will have it own value eg,MyApp2,MyApp3,MyApp4,MyApp5 

and property PropertiesPlaceHolder

 <bean id="placeholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="placeholderPrefix" value="$app{" /> <property name="location" value="classpath:app.properties"/> </bean> 

ObjectName definition

 @ManagedResource(objectName=com.mycompany:name=$app{appName}-MyBean") public class MyBean {} 

Your bean will be called

 com.mycompany +MyApp1-MyBean +MyApp2-MyBean +MyApp3-MyBean +MyApp4-MyBean +MyApp5-MyBean 

You can use more than one property owner.
Works with Spring 4.0.2

0
source

These answers helped me point in the right direction, but there were a few pieces for the installation based on the annotation (I am not using Spring Boot)

Spring Docs on this subject say:

If you prefer to use the annotation-based approach to define your management interfaces, then the convenient subclass MBeanExporter: AnnotationMBeanExporter is available. When defining an instance of this subclass, the namingStrategy configuration, assembler, and the Source attribute are no longer needed, since it will always use standard Java-based annotation-based metadata (auto-detection is also automatically enabled). In fact, instead of defining an MBeanExporter bean, an even simpler syntax is supported by the @EnableMBeanExport @Configuration annotation.

But using @EnableMBeanExport does not allow you to define your own NamingStrategy

So, instead of just @Bean up the @Bean method, which returns my MBeanExporter using a special naming strategy that uses the context path.

 @Configuration public class JmxUtil { @Value("#{servletContext.contextPath}") private String contextPath; private String domain = "foo.bar"; @Bean public MBeanExporter mbeanExporter() { AnnotationMBeanExporter exporter = new AnnotationMBeanExporter(); exporter.setNamingStrategy((managedBean, beanKey) -> { return ObjectNameManager.getInstance(domain, new Hashtable<>(ImmutableMap.of( "name", beanKey, "instance", contextPath ))); }); exporter.setDefaultDomain(domain); return exporter; } } 
0
source

All Articles