有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java为同一服务器上的多个应用程序提供相同的JMX Mbean类

我有5个以上的SpringWeb应用程序,它们都在使用另一个公共库。这个公共库有自己的MBean。由于强制的唯一objectName约束,我的应用程序无法部署在同一服务器上

我使用MBean的方式如下:

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

我希望对所有应用程序使用具有不同对象名的相同MBean类。在不复制MBean的情况下使用它的正确方法是什么

谢谢


共 (5) 个答案

  1. # 1 楼答案

    可以使用占位符基于属性定义简单的命名策略
    每一场战争都会有它;这是自己的应用程序副本。属性
    例如

    带有一个属性文件:app。属性

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

    还有一个房产持有者

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

    定义对象名

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

    你的豆子将被命名为

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

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

  2. # 2 楼答案

    我遇到了同一个问题,并以Cemo's solution为基础。下面是一个示例实现

    背景。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>
    

    多应用元数据命名策略。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

  3. # 3 楼答案

    我已经为定制行为实现了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);
      }
    
  4. # 4 楼答案

    您需要更改mbean导出程序的registering behavoiur

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

    但这仍然意味着只有一个应用程序注册bean。从逻辑上讲,您不能从多个应用程序中拥有多个同名的mbean。如何确定要调用哪个应用程序?将应用程序名称用作mbean名称的前缀

  5. # 5 楼答案

    这些答案帮助我找到了正确的方向,但基于注释的设置缺少了一些内容(但我不使用Spring Boot)

    Spring Docs on this subject说:

    If you prefer using the annotation based approach to define your management interfaces, then a convenience subclass of MBeanExporter is available: AnnotationMBeanExporter. When defining an instance of this subclass, the namingStrategy, assembler, and attributeSource configuration is no longer needed, since it will always use standard Java annotation-based metadata (autodetection is always enabled as well). In fact, rather than defining an MBeanExporter bean, an even simpler syntax is supported by the @EnableMBeanExport @Configuration annotation.

    但是使用@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;
        }
    }