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

时间:2011-08-16 07:44:44

标签: java spring jmx mbeans

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

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

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

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

由于

5 个答案:

答案 0 :(得分:5)

我遇到了同样的问题,并由Cemo's solution构建。这是一个示例实现。

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

这允许设置mbean,如:

package com.foo;

@ManagedResource(description = "Bean description")
public class MyBean {
    ...
}

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

的mbean

答案 1 :(得分:4)

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

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

答案 2 :(得分:0)

您需要更改mbean导出器的registering behavoiur

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

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

答案 3 :(得分:0)

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

使用属性文件:app.properties

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

和一个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

@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

答案 4 :(得分:0)

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

Spring Docs on this subject说:

  

如果您更喜欢使用基于注释的方法来定义管理接口,那么可以使用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;
    }
}