1.需求说明
在java程序代码中获取activemq中每个队列的消息消费情况
2.需要解决以下问题
- activemq远程监控配置
- java代码怎么调用
- 如何实现动态配置相关参数
3.实现步骤
3.1activemq远程配置
进入到activemq安装目录
cd apache-activemq-5.15.6
图为测试环境路径
进入到conf目录下
修改配置文件activemq.xml
vim activemq.xml
1.找到broker节点,增加useJmx="true" brokerName可以修改也可以不修改
2.在broker节点元素内找到<managementContext> 修改
createConnector="true" connectorPort="11099" 其中connectorPort默认为1099
ps:建议修改端口号,这是一个坑,很容易出现被占用的情况导致各种bug报错
修改完成
Esc 键 :wq 保存退出。
重新启动activemq即可
cd ../bin
./activemq stop
./activemq start
./activemq status
3.2java端代码
依赖引入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
yml配置
messages:
basename: i18n/Messages,i18n/Pages
jms:
pub-sub-domain: false # 配置消息的类型,如果是true则表示为topic消息,如果为false表示Queue消息
activemq:
user: admin # 连接用户名
password: admin # 连接密码
broker-url: tcp://172.16.100.152:61616 # 消息组件的连接主机信息
yml新增配置 远程监控(这些参数为自定义,在监控的java代码中会用到)
activeRemote:
connectorPort: 11099
connectorPath: /jmxrmi
jmxDomain: org.apache.activemq
connectorIp: 192.168.1.87
brokerName: localhost
java配置类,通过此方法动态配置activemq的监控参数
package com.huajie.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@Data
@ConfigurationProperties(prefix = "activeRemote")
public class ActivemqUtilConfig {
private String connectorPort;
private String connectorPath ;
private String jmxDomain ;
private String connectorIp;
private String brokerName;
}
远程监控工具类
package com.huajie.utils;
import com.huajie.config.ActivemqUtilConfig;
import org.apache.activemq.broker.jmx.BrokerViewMBean;
import org.apache.activemq.broker.jmx.QueueViewMBean;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.management.MBeanServerConnection;
import javax.management.MBeanServerInvocationHandler;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* 消息队列工具类
*/
@Component
public class ActiveMQUtil {
private static Log log = LogFactory.getLog(ActiveMQUtil.class);
@Autowired
private ActivemqUtilConfig activemqUtilConfig;
public Long getQueueSize(String queueName) {
Map<String, Long> queueMap = getAllQueueSize();
Long queueSize = 0L;
if (queueMap.size() > 0) {
queueSize = queueMap.get(queueName);
}
return queueSize;
}
public boolean checkedEvalQueueFinish() {
long leaderSize = this.getQueueSize("leader.saveQuotaScore.queue");
long leadergroupSize = this.getQueueSize("leadergroup.saveQuotaScore.queue");
if (leaderSize == 0L && leadergroupSize == 0L) {
return true;
} else {
return false;
}
}
public Map<String, Long> getAllQueueSize() {
Map<String, Long> queueMap = new HashMap<String, Long>();
BrokerViewMBean mBean = null;
MBeanServerConnection connection = null;
try {
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://"+ activemqUtilConfig.getConnectorIp()+":" + activemqUtilConfig.getConnectorPort() + activemqUtilConfig.getConnectorPath());
JMXConnector connector = JMXConnectorFactory.connect(url);
connector.connect();
connection = connector.getMBeanServerConnection();
ObjectName name = new ObjectName(activemqUtilConfig.getJmxDomain() + ":brokerName="+activemqUtilConfig.getBrokerName()+",type=Broker");
mBean = MBeanServerInvocationHandler.newProxyInstance(connection, name, BrokerViewMBean.class, true);
} catch (IOException e) {
log.error("ActiveMQUtil.getAllQueueSize", e);
} catch (MalformedObjectNameException e) {
log.error("ActiveMQUtil.getAllQueueSize", e);
}
if (mBean != null) {
for (ObjectName queueName : mBean.getQueues()) {
QueueViewMBean queueMBean = MBeanServerInvocationHandler.newProxyInstance(connection, queueName, QueueViewMBean.class, true);
queueMap.put(queueMBean.getName(), queueMBean.getQueueSize());
// System.out.println("Queue Name --- " + queueMBean.getName());// 消息队列名称
// System.out.println("Queue Size --- " + queueMBean.getQueueSize());// 队列中剩余的消息数
// System.out.println("Number of Consumers --- " + queueMBean.getConsumerCount());// 消费者数
// System.out.println("Number of Dequeue ---" + queueMBean.getDequeueCount());// 出队数
}
}
return queueMap;
}
}
3.3业务调用
在执行操作之前要确定leader.saveQuotaScore.queue和leadergroup.saveQuotaScore.queue两个队列已经全部消费完,所以封装了checkedEvalQueueFinish方法
@Autowired
private ActiveMQUtil activeMQUtil;
@PostMapping("/evalExecuteSubmit")
public @ResponseBody
ResponseBase evalExecuteSubmit(String leadergroupId, String evalYearId, String batch) {
if (activeMQUtil.checkedEvalQueueFinish()) {
//业务代码 update add del
return setResultSuccess("提交成功!");
} else {
return setResultFail("后台数据正在入库,请稍后再试!");
}
}