我有超过5个春季网络应用程序,所有这些都使用另一个公共库。这个公共库有自己的MBean。由于强制唯一objectName约束,我的应用程序无法部署在同一服务器上。
我使用MBean的方式是这样的:
@ManagedResource(objectName = "com.org.city:name=City", description = "City related operations")
我想为所有应用程序使用具有不同objectNames的相同MBean类。在不重复MBean的情况下使用它的正确方法是什么。
由于
答案 0 :(得分:5)
我遇到了同样的问题,并由Cemo's solution构建。这是一个示例实现。
<!-- 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>
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
答案 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)
如果您更喜欢使用基于注释的方法来定义管理接口,那么可以使用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;
}
}