相同的JMX Mbean类用于同一服务器上的许多应用程序

我有超过5个春季网络应用程序,所有这些都使用另一个公共库。 这个公共库有自己的MBean。 由于强制唯一objectName约束,我的应用程序无法部署在同一服务器上。

我使用MBean的方式是这样的:

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

我想为所有应用程序使用具有不同objectNames的相同MBean类。 在不重复我的MBean的情况下使用它的正确方法是什么。

谢谢

我遇到了同样的问题,并建立了Cemo的解决方案 。 这是一个示例实现。

的context.xml

          

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 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); } } 

这允许设置一个mbean,如:

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

它将注册一个对象名为com.foo:name=myBean,type=MyBean,app=CustomAppName的mbean

我已经为自定义行为实现了ObjectNamingStrategy。

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

您需要更改mbean导出器的注册行为 :

  

但这仍然意味着只有一个应用程序注册bean。 并且您无法在逻辑上从多个应用程序中拥有多个具有相同名称的mbean。 如何确定调用哪个应用程序? 使用应用程序名称作为mbean名称的前缀。

您可以使用占位符基于属性定义简单的命名策略。
每场战争都会拥有它;自己的app.properties副本
例如

使用属性文件:app.properties

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

和一个PropertiesPlaceHolder

     

定义objectName

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

你的bean将被命名

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

您可以使用更多的一个属性占位符。
适用于Spring 4.0.2

这些答案帮助我指出了正确的方向,但基于注释的设置缺少一些部分(但我没有使用Spring Boot)

关于这个主题的Spring Docs说:

如果您更喜欢使用基于注释的方法来定义管理接口,那么可以使用MBeanExporter的便捷子类:AnnotationMBeanExporter。 定义此子类的实例时,不再需要namingStrategy,assembler和attributeSource配置,因为它将始终使用基于标准Java注释的元数据(自动检测也始终启用)。 实际上,@ EnableMBeanExport @Configuration注释支持更简单的语法,而不是定义MBeanExporter bean。

但是使用@EnableMBeanExport阻止您定义自己的NamingStrategy

所以不要只是设置一个@Bean方法,它返回我的MBeanExporter ,使用自定义命名策略使用上下文路径。

 @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; } }