如何在使用 spring 引导 jmx 时 return 对象值

how to return object value while using spring boot jmx

我正在使用 spring boot jmx 在数据库发生更改时远程执行该方法。一切正常,当我使用原始数据类型作为 return 值时,我可以使用 windows 中的 jmc.exe 监控我的应用程序。现在我需要 return 对象(不是原始数据类型,而是 class)值作为我方法的 return。实际上这个对象和我的 class 在同一个包里。但是当我 运行 远程使用 jmx 的方法时,我得到

java.rmi.UnmarshalException: error unmarshalling return; nested exception is: 
java.lang.ClassNotFoundException: com.ff.KeyValue (no security manager: RMI class loader disabled).

我的代码如下

@Service
@ManagedResource(description = "JMX managed resource for updating map when database is updated",
        objectName = "chargeCode:name=ChargeCodeService")
public class ChargeCodeService {

    private static final Logger logger = LoggerFactory.getLogger(ChargeCodeService.class);

    private final ChargeCodeRepository chargeCodeRepository;
    private Map<String, KeyValue<String,String>> chargeCodeMap = new HashMap<>();

    @Autowired
    public ChargeCodeService(ChargeCodeRepository chargeCodeRepository) {
        this.chargeCodeRepository = chargeCodeRepository;
    }

    @PostConstruct
    @ManagedOperation
    public Map<String, KeyValue<String,String>> chargeCodMapInitial() {
        logger.info("ready to read chargeCode data from database. this operation will do when an update occure in database");
        List<ChargeCode> chargeCodes = chargeCodeRepository.findAll();
        for (ChargeCode chargeCode : chargeCodes) {
            chargeCodeMap.put(chargeCode.getIacChargeCode(),new KeyValue<>( chargeCode.getBankChargeCode(),chargeCode.getTopupProvider()));
        }
        return chargeCodeMap;
    }

    @ManagedAttribute
    public Map<String, KeyValue<String, String>> getChargeCodeMap() {
        return chargeCodeMap;
    }
}

KeyValue class如下:

public class KeyValue<K, V> implements Map.Entry<K, V>, Serializable {

    private static final long serialVersionUID = -2610138893852455839L;

    private K key;
    private V value;

    public KeyValue() {
    }

    public KeyValue(K key, V value)
    {
        this.key = key;
        this.value = value;
    }

  getter,setter;
}

您必须 return CompositeData 或 TabularDataSupport 作为您的 return 类型。以下代码演示了这两种方法,应该对您有用。如果您有任何问题,请告诉我。

package com.example.demo;

import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedOperationParameter;
import org.springframework.jmx.export.annotation.ManagedOperationParameters;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.stereotype.Component;

import javax.management.openmbean.*;

@Component
@ManagedResource(objectName="com.example.demo.jmx:name=ServerManager",
        description="Server manager.")
public class SampleOperation {
    private static final String[] itemNames = new String[] { "name", "age" };
    private static final String[] itemDescription = new String[] { "Your name", "Your age" };
    private static final OpenType<?>[] itemTypes = new OpenType[] {
            SimpleType.STRING,
            SimpleType.INTEGER
    };

    public static final String IAC_CHARGE_CODE = "IacChargeCode";
    public static final String BANK_CHARGE_CODE = "BankChargeCode";
    public static final String TOP_UP_PROVIDER = "TopUpProvider";
    public static final String[] rowItemNames = new String[] { IAC_CHARGE_CODE, BANK_CHARGE_CODE, TOP_UP_PROVIDER };
    public static final String[] rowItemDescriptions = new String[] {
            "Iac charge code",
            "Bank charge code",
            "Top up provider"
    };

    @ManagedOperation(description="Get the complex object.")
    @ManagedOperationParameters({
            @ManagedOperationParameter(name="name", description= "Your name."),
            @ManagedOperationParameter(name="age", description= "Your age.")})
    public CompositeData simpleData(String name, int age) throws Exception {
        CompositeType compositeType = new CompositeType(
                "NameAndAge",
                "name and age",
                itemNames, itemDescription, itemTypes);

        CompositeData data = new CompositeDataSupport(compositeType, itemNames, new Object[] {
                name, age
        });
        return data;
    }

    @ManagedOperation(description="Retrieve recodes from DB.")
    public TabularDataSupport tabular() throws OpenDataException {
        OpenType<?>[] rowItemTypes = new OpenType[]{
                SimpleType.STRING, SimpleType.STRING, SimpleType.STRING
        };

        CompositeType compositeRowType = new CompositeType(
                "chargeRow",
                "some row",
                rowItemNames,
                rowItemDescriptions,
                rowItemTypes);
        TabularType tabularType = new TabularType(
                "charge table",
                "Sample table of charge",
                compositeRowType,
                rowItemNames);
        TabularDataSupport rows = new TabularDataSupport(tabularType);

        rows.putAll(new CompositeData[]{
                new CompositeDataSupport(compositeRowType, rowItemNames, new Object[]{
                        "charge code #1", "bank charge code #1", "Top up #1"
                }),
                new CompositeDataSupport(compositeRowType, rowItemNames, new Object[]{
                        "charge code #2", "bank charge code #2", "Top up #2"
                }),
                new CompositeDataSupport(compositeRowType, rowItemNames, new Object[]{
                        "charge code #3", "bank charge code #3", "Top up #3"
                }),
        });
        return rows;
    }
}