一个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();
}
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注册开放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);
}
}