创建自己的MBean

借助Spring,可以很容易地将任意bean导出为JMX MBean。我们唯一需要做的就是在bean类上添加@ManagedResource注解,然后在方法或属性上添加@ManagedOperation或@ManagedAttribute。Spring会处理剩余的事情。

例如,我们想要提供一个MBean,用来跟踪通过Taco Cloud创建了多少个taco订单,那么可以定义一个服务bean,在这个服务中保存已创建taco的数量。程序清单17.1展现了该服务。

程序清单17.1 统计已创建taco订单数量的MBean
package tacos.jmx;

import java.util.concurrent.atomic.AtomicLong;
import org.springframework.data.rest.core.event.AbstractRepositoryEventListener;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.stereotype.Service;
import tacos.Taco;
import tacos.data.TacoRepository;

@Service
@ManagedResource
public class TacoCounter
       extends AbstractRepositoryEventListener<Taco> {

  private AtomicLong counter;
  public TacoCounter(TacoRepository tacoRepo) {
    tacoRepo
        .count()
        .subscribe(initialCount -> {
            this.counter = new AtomicLong(initialCount);
        });
  }

  @Override
  protected void onAfterCreate(Taco entity) {
    counter.incrementAndGet();
  }

  @ManagedAttribute
  public long getTacoCount() {
    return counter.get();
  }

  @ManagedOperation
  public long increment(long delta) {
    return counter.addAndGet(delta);
  }

}

TacoCounter类使用了@Service注解,所以它会被组件扫描功能发现,并且注册一个实例作为bean存放到Spring应用上下文中。它还使用了@ManagedResource注解,表明这个bean是一个MBean。作为MBean,它暴露了一个属性和一个操作。getTacoCount()方法使用了@ManagedAttribute注解,会暴露为一个MBean属性;increment()方法使用了@ManagedOperation注解,会暴露为MBean操作。图17.4展现了TacoCounter MBean在JConsole中的样子。

image 2024 03 14 15 44 34 442
Figure 1. 图17.4 在JConsole中看到的TacoCounter的操作和属性

关于TacoCounter,还有一个技巧,不过与JMX并没有什么关系——它扩展了Abstract RepositoryEventListener,每当通过TacoRepository保存Taco的时候,它都会得到通知。在本例中,创建和保存新Taco对象时,onAfterCreate()方法会被调用,我们在这里让计数器增加1。AbstractRepositoryEventListener还提供了多个方法来处理对象创建、保存和删除前后的事件。

使用MBean的操作和属性在很大程度上是一个拉取操作。换句话说,如果MBean属性的值发生了变化,除非通过JMX客户端查看该属性,否则我们也不会知道。接下来,我们换一个话题,看一下如何将MBean的通知推送至JMX客户端。