Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何使自定义Spring MBeanExporter使用@Managed。。。关于候选类的注释_Java_Spring_Jmx_Mbeans_Mbeanexporter - Fatal编程技术网

Java 如何使自定义Spring MBeanExporter使用@Managed。。。关于候选类的注释

Java 如何使自定义Spring MBeanExporter使用@Managed。。。关于候选类的注释,java,spring,jmx,mbeans,mbeanexporter,Java,Spring,Jmx,Mbeans,Mbeanexporter,我已经编写了一个定制的Spring MBeanExporter,它获取预先创建的对象的集合,并为它们创建MBean。显然,它使用默认策略来确定属性和操作,只是获取关联类的现有属性和操作 我只是有一个AfterPropertieSet方法,它做一些工作,填充基本bean列表,然后调用它的超类方法。这相当有效 我现在想看看我是否能让它利用任何@Managed。。。关联类上的注释。在我的第一次尝试中,我只是将预期的注释放在关联的类上,而不改变bean列表的填充和处理方式。不幸的是,这不起作用。我向类、

我已经编写了一个定制的Spring MBeanExporter,它获取预先创建的对象的集合,并为它们创建MBean。显然,它使用默认策略来确定属性和操作,只是获取关联类的现有属性和操作

我只是有一个AfterPropertieSet方法,它做一些工作,填充基本bean列表,然后调用它的超类方法。这相当有效

我现在想看看我是否能让它利用任何@Managed。。。关联类上的注释。在我的第一次尝试中,我只是将预期的注释放在关联的类上,而不改变bean列表的填充和处理方式。不幸的是,这不起作用。我向类、属性和操作添加了几个描述属性,但这些属性没有显示在VisualVM中

我能做些什么让MBeanExporter机制使用@Managed。。。关联类上的注释

注意,我当前的类扩展了MBeanExporter。如果我将其更改为extend AnnotationMBeanExporter,那么它将在没有@Managed的类上失败。。。注释。我需要一些默认MBeanExporter的功能,除非它找到@Managed。。。类中的注释

我想我需要展示一些代码,但这大部分只是伪代码

我的MBeanExporter看起来像这样:

public class MyMBeanExporter extends MBeanExporter {

@Override
public void afterPropertiesSet() {
    // Do some pre-work to determine the list of beans to use.
    Map<String, Object> beans   = new HashMap<String, Object>();
    ... stuff
    setBeans(beans);

    // Now let the superclass create mbeans for all of the beans we found.
    super.afterPropertiesSet();
}
@ManagedResource(objectName = ":name=fancystuff", description = "This is some stuff")
public class Stuff {
    private int howMuchStuff;

    @ManagedAttribute(description = "This tells us how much stuff we have")
    public int getHowMuchStuff() { return howMuchStuff; }

    public void setHowMuchStuff(int howMuchStuff) { this.howMuchStuff = howMuchStuff; }

    @ManagedOperation(description = "Use this to add more stuff")
    public void makeSomeMoreStuff(int stuffToAdd) {
        howMuchStuff    += stuffToAdd;
    }
}
InvalidMetadataException: No ManagedResource attribute found for class: class ...
在VisualVM中呈现时,@Managed。。。使用注释。我可以确定这一点,因为生成的ObjectName不是我在@ManagedResource注释中指定的覆盖值

如果我改为将基类更改为AnnotationMBeanExporter,那么与该类关联的bean将获得我在注释中指定的元数据。但是,与没有@ManagedResource注释的类关联的所有其他bean都会失败,出现如下异常:

public class MyMBeanExporter extends MBeanExporter {

@Override
public void afterPropertiesSet() {
    // Do some pre-work to determine the list of beans to use.
    Map<String, Object> beans   = new HashMap<String, Object>();
    ... stuff
    setBeans(beans);

    // Now let the superclass create mbeans for all of the beans we found.
    super.afterPropertiesSet();
}
@ManagedResource(objectName = ":name=fancystuff", description = "This is some stuff")
public class Stuff {
    private int howMuchStuff;

    @ManagedAttribute(description = "This tells us how much stuff we have")
    public int getHowMuchStuff() { return howMuchStuff; }

    public void setHowMuchStuff(int howMuchStuff) { this.howMuchStuff = howMuchStuff; }

    @ManagedOperation(description = "Use this to add more stuff")
    public void makeSomeMoreStuff(int stuffToAdd) {
        howMuchStuff    += stuffToAdd;
    }
}
InvalidMetadataException: No ManagedResource attribute found for class: class ...
我的临时解决方法只是定义我的MBeanExporter子类,以便它可以作为普通MBeanExporter或AnnotationMBeanExporter,具体取决于构造函数标志。然后,我可以简单地定义它的两个实例,一个有标志,另一个没有标志,并且有一组不同的处理路径。这很有效

我接下来要尝试的是使用一个假的MBeanExporter,它在内部管理一个MBeanExporter和一个AnnotationMBeanExporter。它将构建初始bean列表,然后处理每个bean,查看与bean关联的类,以查看@ManagedResource注释是否存在。这将指示它是否会出现在要由AnnotationMBeanExporter处理的bean列表中,还是出现在常规bean列表中

更新: 我遇到了这个策略的问题,因为我不能仅仅创建一个原始的AnnotationMBeanExporter并调用AfterPropertieSet。它失败于:

MBeanExportException: Cannot autodetect MBeans if not running in a BeanFactory

好的,我想我现在有了一些有效的方法。我不确定这是否都是正确的。如Martin所述,我创建了新的汇编器和命名策略类,这些类结合了默认和注释变体的行为,因此,如果范围中的类具有ManagedResource注释,那么它将使用MetadataMBeanInfoAssembler和MetadataNamingStrategy中的行为,否则,将简化反汇编程序和键命名策略

命名策略子类的实现有点简单,但汇编程序实现有点烦人,因为我只需复制MetadataMBeanifoAssembler中所有被重写的方法体,并将它们插入类注释的包装检查中。没有办法简单地拥有一个嵌入式MetadataMBeanInfoAssembler并在其上调用方法

下面是我的命名策略子类,我可以使用一些提示来说明如何让代码示例清晰地显示在这里:

package <packagepath>.mbeans;

import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;

import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.jmx.export.metadata.JmxAttributeSource;
import org.springframework.jmx.export.naming.KeyNamingStrategy;
import org.springframework.jmx.export.naming.MetadataNamingStrategy;
import org.springframework.jmx.export.naming.ObjectNamingStrategy;

public class MetadataOrKeyNamingStrategy implements ObjectNamingStrategy, InitializingBean {
private MetadataNamingStrategy  metadataNamingStrategy  = new MetadataNamingStrategy();
private KeyNamingStrategy       keyNamingStrategy       = new KeyNamingStrategy();

public MetadataOrKeyNamingStrategy(JmxAttributeSource attributeSource) {
    metadataNamingStrategy.setAttributeSource(attributeSource);
}

@Override
public void afterPropertiesSet() throws Exception {
    metadataNamingStrategy.afterPropertiesSet();
    keyNamingStrategy.afterPropertiesSet();
}

/**
 * Specify the default domain to be used for generating ObjectNames
 * when no source-level metadata has been specified.
 * <p>The default is to use the domain specified in the bean name
 * (if the bean name follows the JMX ObjectName syntax); else,
 * the package name of the managed bean class.
 */
public void setDefaultDomain(String defaultDomain) {
    metadataNamingStrategy.setDefaultDomain(defaultDomain);
}

@Override
public ObjectName getObjectName(Object managedBean, String beanKey)
    throws MalformedObjectNameException {
    Class<?> managedClass = AopUtils.getTargetClass(managedBean);
    if (managedClass.getAnnotation(ManagedResource.class) != null)
    return metadataNamingStrategy.getObjectName(managedBean, beanKey);
    return keyNamingStrategy.getObjectName(managedBean, beanKey);
}
}
建造商团体:

setNamingStrategy(metadataOrKeyNamingStrategy);
setAssembler(metadataOrSimpleReflectiveMBeanInfoAssembler);
setAutodetectMode(AUTODETECT_ALL);
然后:

public void setDefaultDomain(String defaultDomain) {
    this.metadataOrKeyNamingStrategy.setDefaultDomain(defaultDomain);
}

@Override
public void setBeanFactory(BeanFactory beanFactory) {
    super.setBeanFactory(beanFactory);
    this.annotationSource.setBeanFactory(beanFactory);
}

@Override
public void afterPropertiesSet() {
    // Find some beans that should be registered
    setBeans(beans);

    // Now let the superclass create mbeans for all of the beans we found.
    super.afterPropertiesSet();
}

我可以用一些想法来简化这个过程。

好的,这里是另一个尝试。我不喜欢这样一个事实:我最终不得不从两个备选实现中的任何一个复制方法体。我的结论是,如果我将strategy和assembler自定义类都设置为元数据版本的子类,就可以减少这种复制。其基本思想是,在检查类上是否存在@ManagedResource注释之后,我可以调用超类方法,或者内联非元数据版本,在所有情况下,非元数据版本的代码都少于元数据版本

对于strategy类,由于非元数据版本中的相关方法是公共的,因此我仍然可以创建strategy类的本地实例,只调用相关方法,而不是内联方法体

对于assembler类,我发现我不必复制元数据版本中任何方法的主体,但我 我发现我必须重写额外的方法,并且我必须在超类中复制一个方法的方法体,因为我不能直接访问它。生成的类比我第一次尝试的要短一些,所以我认为它更好,即使有那些稍微粗糙的部分

为了彻底清理这个问题,必须将其集成到Spring中,以实现最佳重构。这提供的功能似乎是一件好事,因此我将提交一个票证,至少要求提供此功能,并且我将在票证中发布这些类

在这个版本中,我将实现完全重构为AnnotationOrDefaultMBeanExporter类,然后我的实际应用程序特定类扩展了我不需要在这里显示的类

以下是主要的出口商类别:

package <package>;

import java.util.logging.Logger;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.jmx.export.MBeanExporter;
import org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource;
import org.springframework.jmx.export.naming.MetadataNamingStrategy;

public class AnnotationOrDefaultMBeanExporter extends MBeanExporter {

protected static Logger logger = Logger.getLogger(AnnotationOrDefaultMBeanExporter.class.getName());
private AnnotationJmxAttributeSource annotationSource = new AnnotationJmxAttributeSource();
protected MetadataOrKeyNamingStrategy metadataOrKeyNamingStrategy = new MetadataOrKeyNamingStrategy(annotationSource);
protected MetadataOrSimpleReflectiveMBeanInfoAssembler metadataOrSimpleReflectiveMBeanInfoAssembler = new MetadataOrSimpleReflectiveMBeanInfoAssembler(annotationSource);

public AnnotationOrDefaultMBeanExporter() {
    setNamingStrategy(metadataOrKeyNamingStrategy);
    setAssembler(metadataOrSimpleReflectiveMBeanInfoAssembler);
    setAutodetectMode(AUTODETECT_ALL);
}

/**
 * Specify the default domain to be used for generating ObjectNames
 * when no source-level metadata has been specified.
 * <p>The default is to use the domain specified in the bean name
 * (if the bean name follows the JMX ObjectName syntax); else,
 * the package name of the managed bean class.
 * @see MetadataNamingStrategy#setDefaultDomain
 */
public void setDefaultDomain(String defaultDomain) {
    this.metadataOrKeyNamingStrategy.setDefaultDomain(defaultDomain);
}

@Override
public void setBeanFactory(BeanFactory beanFactory) {
    super.setBeanFactory(beanFactory);
    this.annotationSource.setBeanFactory(beanFactory);
}
}
下面是策略课。这里有点棘手的一点是用抛出RuntimeException来包装一个选中的异常

package <package>;

import java.io.IOException;

import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;

import org.springframework.aop.support.AopUtils;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.jmx.export.metadata.JmxAttributeSource;
import org.springframework.jmx.export.naming.KeyNamingStrategy;
import org.springframework.jmx.export.naming.MetadataNamingStrategy;

public class MetadataOrKeyNamingStrategy extends MetadataNamingStrategy {
private KeyNamingStrategy       keyNamingStrategy       = new KeyNamingStrategy();

public MetadataOrKeyNamingStrategy() { }

public MetadataOrKeyNamingStrategy(JmxAttributeSource attributeSource) {
    super(attributeSource);
}

@Override
public void afterPropertiesSet() {
    super.afterPropertiesSet();
    try {
    keyNamingStrategy.afterPropertiesSet();
    }
    catch (IOException ex) {
    throw new RuntimeException(ex);
    }
}

@Override
public ObjectName getObjectName(Object managedBean, String beanKey)
    throws MalformedObjectNameException {
    Class<?> managedClass = AopUtils.getTargetClass(managedBean);
    if (managedClass.getAnnotation(ManagedResource.class) != null)
    return super.getObjectName(managedBean, beanKey);
    return keyNamingStrategy.getObjectName(managedBean, beanKey);
}
}
这是汇编器类:

package <package>;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;

import javax.management.Descriptor;

import org.springframework.aop.support.AopUtils;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler;
import org.springframework.jmx.export.metadata.JmxAttributeSource;

public class MetadataOrSimpleReflectiveMBeanInfoAssembler extends MetadataMBeanInfoAssembler {

public MetadataOrSimpleReflectiveMBeanInfoAssembler() { }

public MetadataOrSimpleReflectiveMBeanInfoAssembler(JmxAttributeSource attributeSource) {
    super(attributeSource);
}

@Override
protected boolean includeReadAttribute(Method method, String beanKey) {
    if (method.getDeclaringClass().getAnnotation(ManagedResource.class) != null)
    return super.includeReadAttribute(method, beanKey);
    return true;
}

@Override
protected boolean includeWriteAttribute(Method method, String beanKey) {
    if (method.getDeclaringClass().getAnnotation(ManagedResource.class) != null)
    return super.includeWriteAttribute(method, beanKey);
    return true;
}

@Override
protected boolean includeOperation(Method method, String beanKey) {
    if (method.getDeclaringClass().getAnnotation(ManagedResource.class) != null)
    return super.includeOperation(method, beanKey);
    return true;
}

@Override
protected String getDescription(Object managedBean, String beanKey) {
    if (managedBean.getClass().getAnnotation(ManagedResource.class) != null)
    return super.getDescription(managedBean, beanKey);
    return superSuperGetDescription(managedBean, beanKey);
}

/** Copied from AbstractMBeanInfoAssembler.getDescription(), the super.superclass of this class, which can't be easily called. */
private String superSuperGetDescription(Object managedBean, String beanKey) {
    String targetClassName = getTargetClass(managedBean).getName();
    if (AopUtils.isAopProxy(managedBean)) {
    return "Proxy for " + targetClassName;
    }
    return targetClassName;
}

@Override
protected String getAttributeDescription(PropertyDescriptor propertyDescriptor, String beanKey) {
    Method readMethod = propertyDescriptor.getReadMethod();
    if (readMethod != null && readMethod.getDeclaringClass().getAnnotation(ManagedResource.class) != null)
    return super.getAttributeDescription(propertyDescriptor, beanKey);
    return propertyDescriptor.getDisplayName();
}

@Override
protected String getOperationDescription(Method method, String beanKey) {
    if (method.getDeclaringClass().getAnnotation(ManagedResource.class) != null)
    return super.getOperationDescription(method, beanKey);
    return method.getName(); 
}

@Override
protected void populateAttributeDescriptor(Descriptor desc, Method getter, Method setter, String beanKey) {
    Method  methodToUse = getter;
    if (methodToUse == null)
    methodToUse = setter;
    if (methodToUse != null) {
    if (methodToUse.getDeclaringClass().getAnnotation(ManagedResource.class) != null)
        super.populateAttributeDescriptor(desc, getter, setter, beanKey);
    else
        applyDefaultCurrencyTimeLimit(desc);
    }
    else
    applyDefaultCurrencyTimeLimit(desc);
}

@Override
protected void populateMBeanDescriptor(Descriptor descriptor, Object managedBean, String beanKey) {
    if (managedBean.getClass().getAnnotation(ManagedResource.class) != null)
    super.populateMBeanDescriptor(descriptor, managedBean, beanKey);
    else
    applyDefaultCurrencyTimeLimit(descriptor);
}

@Override
protected void populateOperationDescriptor(Descriptor desc, Method method, String beanKey) {
    if (method != null) {
    if (method.getClass().getAnnotation(ManagedResource.class) != null)
        super.populateOperationDescriptor(desc, method, beanKey);
    else
        applyDefaultCurrencyTimeLimit(desc);
    }
    else
    applyDefaultCurrencyTimeLimit(desc);
}
}

请发一些代码。如果是其他人,马丁,我会回答的,是不是很明显今天上午晚些时候我将整理一些示例并编辑这篇文章。AnnotationMBeanExporter所做的基本工作是为namingStrategy和assembler属性设置一些特定的策略。最简单的方法是创建这些策略接口MBeanInfoAssembler和ObjectNamingStrategy的组合实现。然后可以使用注释MBeanExporter和MBeanExporter中的默认值对其进行注入/硬编码。首先,让它检查注释,如果没有,则退回到MBeanExporter中使用的默认策略。这次尝试中令人痛苦的是,我必须在MetadataMBeanInfoAssembler中使用的所有相关方法都受到保护,因此我不能只使用MetadataMBeanfoAssembler的嵌入式实例。我必须复制这些方法的所有代码。