JMX自定义MXBean

MXBean接口

一个MBean由一个MBean接口(该MBean接口列出了所有被暴露的属性和操作对应的方法)和一个class(这 个class实现了这个MBean接口并提供被监测资源的功能)组成。

下面的章节展示了一个MBean例子,以及管理该MBean的一个简单的 JMX agent。

public interface MXBeanBase {

  /**
   * 加载元素
   */
  void load();
}

ServerMonitor 接口实现有两种方式:

1. @MXBean注解

2. 接口命名

根据JMX规范,接口名字加上后缀 MXBean ,实现类必须是接口名去掉MBean

下面是基于注解的接口类

@MXBean
public interface ServerMonitor extends MXBeanBase {

  /**
   * 加载
   */
  @Override
  void load();

  /**
   * 加载-按照类型
   *
   * @param type
   * @see MonitorType
   */
  void load(MonitorType type);
  /**
   * 获取接口名称
   *
   * @return
   */
  String getApiName();
  /**
   * 获取QPS
   */
  Double getQps();
  /**
   * 获取请求返回总数
   */
  Long getResTotalNum();

  /**
   * 获取请求数-成功
   */
  Long getResSucNum();

  /**
   * 获取请求数-失败
   */
  Long getResFailNum();

  /**
   * 获取请求数-空
   */
  Long getResNullNum();

  /**
   * 获取请求数-非空
   */
  Long getResNotNullNum();

}

MXBean实现类

public class ServerMonitorForUserProfile implements ServerMonitor {

  private static final Logger LOG = LoggerFactory.getLogger(ServerMonitorForUserProfile.class);

  private List serverMonitorBeans = new ArrayList<>();

  @Override
  public void load() {
    List monitor_profiles = UserProfileAspect.getMonitor_profiles();
    serverMonitorBeans.clear();
    monitor_profiles.parallelStream().forEach(e -> {
      ServerMonitorBean serverMonitorBean = new ServerMonitorBean();
      serverMonitorBean.setApiName(e.getApiName());
      serverMonitorBean.setQps(e.getQps());
      serverMonitorBean.setResTotalNum(e.getResTotalNum());
      serverMonitorBean.setResSucNum(e.getResSucNum());
      serverMonitorBean.setResFailNum(e.getResFailNum());
      serverMonitorBean.setResNullNum(e.getResNullNum());
      serverMonitorBean.setResNotNullNum(e.getResNotNullNum());
      serverMonitorBeans.add(serverMonitorBean);
    });
    LOG.info(getMonitorInfoJson());
  }


  @Override
  public List getMonitorInfos() {
    return serverMonitorBeans;
  }

  public String getMonitorInfoJson() {
    return JSON.toJSONString(serverMonitorBeans);
  }
}

自定义复杂类型

@Setter
@Getter
@NoArgsConstructor
public class ServerMonitorBean {

  private String apiName;
  private Double qps;
  private Long qpsNum;
  private Long resTotalNum;
  private Long resSucNum;
  private Long resFailNum;
  private Long resNullNum;
  private Long resNotNullNum;

  @ConstructorProperties({"apiName", "qps", "qpsNum", "resTotalNum",
      "resSucNum", "resFailNum", "resNullNum", "resNotNullNum"})
  public ServerMonitorBean(String apiName, Double qps, Long qpsNum, Long resTotalNum,
      Long resSucNum, Long resFailNum, Long resNullNum, Long resNotNullNum) {
    this.apiName = apiName;
    this.qps = qps;
    this.qpsNum = qpsNum;
    this.resTotalNum = resTotalNum;
    this.resSucNum = resSucNum;
    this.resFailNum = resFailNum;
    this.resNullNum = resNullNum;
    this.resNotNullNum = resNotNullNum;
  }

MBeanServer注册

使用MBeanServer注册开放jmx接口实现类

   这个JMX agent,Main,首先通过调用java.lang.management.ManagementFactory类的getPlatformMBeanServer()方法,来获取一个MXBeanSerer,该MBeanSerer已经由Java SE平台创建并初始化。如果平台还没创建MBeanSerer,那么 getPlatformMBeanServer()就通过调用JMX方法MBeanServerFactory.createMBeanServer(),自动地创建一个MBeanServer。由Main获取的MBeanServer instance被叫做mbs。

        接着,Main 为 将要被创建的MBean instance 定义了一个对象名。每个JMX MBean都必须有一个对象名。对象名是JMX类ObjectName 的一个实例,必须遵守定义在JMX规范中的语法。也就是说,对象名必须包含一个domain以及一个"键-值"属性列表。由Main定义的这个对象名中,domain是com.example (包含这个MBean例子的包名)。此外,"键-值"属性 声明了该对象的类型是为MXBeanBase。

        接着创建了MXBeanBase对象的一个实例,命名为monitorForUserProfile。然后,通过将这个叫做monitorForUserProfile 的MXBeanBase对象 及其 对象名传入JMX方法MBeanServer.registerMBean(),该Hello对象,就被注册为MBean Server mbs中的一个MBean,其对象名为nameForUserProfile。

        当该 MXBeanBase注册到了该 MBeanServer中之后,Main简单地等待对MXBeanBase进行管理操作。在这个例子中,这些管理操作是 调用load()以及读写属性的值。

@Component("ServerMonitorManager")
public class ServerMonitorManager {

  private static final Logger LOG = LoggerFactory.getLogger(ServerMonitorManager.class);


  static Map monitorMap;

  public static void main(String[] args) {
    initMbServerForMonitor();
    return;
  }

  @PostConstruct
  public void init() {
    //1. 初始化map容器
    monitorMap = new HashMap<>();
    //2. 初始化MBeanServer
    LOG.info("ServerMonitorManager#initMbServerForMonitor() init...");
    initMbServerForMonitor();
    LOG.info("ServerMonitorManager#initMbServerForMonitor() init: success, size: {}", monitorMap.size());
    //3. 记录数刷新
    recordLoad();
  }

  public static void initMbServerForMonitor() {
    try {
      MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();

      MXBeanBase monitorForUserProfile = new ServerMonitorForUserProfile();
      String nameForUserProfile = "com.apus.hella:type=UserProfile";
      MBeanRegister4ServerMonitor(mbs, monitorForUserProfile, nameForUserProfile);
    } catch (Exception e) {
      LOG.error(e.getMessage(), e);
    }
  }

  private static void MBeanRegister4ServerMonitor(MBeanServer mbs, MXBeanBase monitor, String name)
      throws MalformedObjectNameException, InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException {
    ObjectName objectName = new ObjectName(name);
    mbs.registerMBean(monitor, objectName);
    monitorMap.put(name, monitor);
  }

  /**
   * 定时刷新记录值
   */
  public void recordLoad() {
    final long delay = 0;
    final long period = 10 * 1000;
    new java.util.Timer().schedule(new TimerTask() {
      @Override
      public void run() {
        monitorMap.forEach((k, v) -> v.load());
      }
    }, delay, period);
  }
}

 

你可能感兴趣的:(JAVA)