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

发布于 2024-11-29 22:19:32 字数 341 浏览 1 评论 0原文

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

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

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

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

谢谢

I have more than 5 spring web application and all of them are utilizing another common library. This common library has its own MBeans. Because of mandatory unique objectName constraint, my applications could not be deployed on same server.

The way I am using MBeans are like this:

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

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

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

温暖的光 2024-12-06 22:19:32

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

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 {
    ...
}

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

I ran into the same issue, and built off of Cemo's solution. Here is a sample 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 setting up an mbean like:

package com.foo;

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

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

波浪屿的海角声 2024-12-06 22:19:32

我已经为自定义行为实现了 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);
  }

I have implemented ObjectNamingStrategy for custom behaviour.

   @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);
  }
疾风者 2024-12-06 22:19:32

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

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

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

You need to change the registering behavoiur of the mbean exporter:

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

But this will still mean only one application registers the bean. And you can't logically have more than one mbean with the same name from multiple applications. How will be determined which application to invoke? Use the application name as a prefix to the mbean name.

记忆里有你的影子 2024-12-06 22:19:32

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

使用属性文件: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

You can define a simple naming strategy based on properties using place holder(s).
Every war will have it;s own copy of the app.properties
E.g.

With a properties file :app.properties

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

and a PropertiesPlaceHolder

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

Defining objectName

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

Your bean will be named

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

You can use more the one property place holder.
Works with Spring 4.0.2

梦幻的味道 2024-12-06 22:19:32

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

关于此主题的 Spring 文档 说:

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

These answers helped point me in the right direction, but there were a few pieces missing for an Annotation based setup (I'm not using Spring Boot however)

The Spring Docs on this subject say:

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.

But using @EnableMBeanExport prevents you from having the ability of defining your own NamingStrategy

So Instead of just setup a @Bean method that returns my MBeanExporter with a custom 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;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文