ActiveMQ概述
Apache ActiveMQ是Apache软件基金会所研发的开放源码消息中间件;由于ActiveMQ是一个纯Java程序,因此只需要操作系统支持Java虚拟机,ActiveMQ便可执行。
特点:
1、支持多种语言编写客户端
2、对spring的支持,很容易和spring整合
3、支持多种传输协议:TCP,SSL,NIO,UDP等
4、支持AJAX
消息形式:
1、点对点(queue)
2、一对多(topic)
ActiveMQ原理
- 应用程序A和应用程序B运行于同一系统A,它们之间可以借助消息队列技术进行彼此的通讯;
- 应用程序A向队列1发送一条信息,而当应用程序B需要时就可以得到该信息。
- 其次是远程通讯的情况,如果信息传输的目标改为在系统B上的应用程序C,这种变化不会对应用程序A产生影响。
- 应用程序A向队列2发送一条信息,系统A的MQ发现Q2所指向的目的队列实际上位于系统B,它将信息放到本地的一个特殊队列-传输队列(Transmission Queue)。我们建立一条从系统A到系统B的消息通道,消息通道代理将从传输队列中读取消息,并传递这条信息到系统B,然后等待确认。只有MQ接到系统B成功收到信息的确认之后,它才从传输队列中真正将该信息删除。
- 如果通讯线路不通,或系统B不在运行,信息会留在传输队列中,直到被成功地传送到目的地。
- 这是MQ最基本而最重要的技术–确保信息传输,并且是一次且仅一次(once-and-only-once)的传递。MQ提供了用于应用集成的松耦合的连接方法,因为共享信息的应用不需要知道彼此物理位置(网络地址);不需要知道彼此间怎样建立通信;不需要同时处于运行状态;不需要在同样的操作系统或网络环境下运行。
ActiveMQ操作及企业实际运用
明白下面的各个角色的职责
- JMS框架基本角色和编程模块
- JMS Message Producers : 消息生产者,向消息队列提供消息
- JMS Provider(Broker) : JMS提供商,如ActiveMQ,提供JMS Queues/Topics服务
- JMS Message listener/Consumer :接收并使用消息
queue的使用
导入jar包
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-all</artifactId>
</dependency>
业务逻辑简单提一下,商户支付一笔订单后,使用MQ队列创建流水明细。
这段代码,支付完成后,传递创建支付流水需要的参数。
//付款方流水
payFundBlotterService.constructorBillWater(payUniformOrder.getPrice(),3,
payUniformOrder.getSubject()
+"-钱包支付",
payUniformOrder.getPayeeCode(),
payUniformOrder.getPayerCode(),
transCodeId,
payUniformOrder.getUniformOrderId(),message,status,
null,new BigDecimal("0.00"),user);
//收款方流水
payFundBlotterService.constructorBillWater(payUniformOrder.getPrice(),2,
payUniformOrder.getSubject()
+"-钱包收款",
payUniformOrder.getPayerCode(),
payUniformOrder.getPayeeCode(),
transCodeId,
payUniformOrder.getUniformOrderId(),message,status,
null,new BigDecimal("0.00"),user);
下面是构造流水明细函数
/*
* @Author ouyang
* @Description //TODO 构造流水明细单,收款方和付款方
* @Date 11:05 2019/7/23
* @Param [Amount 金额
*orderType 订单类型
*title 操作标题
*transactionAccount 交易账户
*transCodeId 交易流水号 充值,提现(银行订单号)
*businessPayOrderId 支付单号 充值,提现等
*message 提示语句
*status 交易状态
* 0 (充值)待充值 (提现)审批中
* 1 (充值)银行处理中 (提现)银行处理中
* 2 (充值)充值成功 (提现)成功
* 3 (充值)充值失败 (提现)失败
*FundId 银行账户ID
* serviceFee 服务费
* @return com.ivyb2b.pay.entity.PayFundBlotter
**/
public void constructorBillWater(BigDecimal Amount, int orderType,
String title, String transactionAccount,
String mchId,
String transCodeId,
String businessPayOrderId,
String message, Integer status,
String FundId,
BigDecimal serviceFee, Identity user) {
PayFundBlotter Blotter = new PayFundBlotter();
Blotter.setAmount(Amount);
Blotter.setOrdertype(orderType);
Blotter.setTransCodeId(transCodeId);
Blotter.setBlotterId(getBusinessSystemid());
Blotter.setFundId(FundId);
Blotter.setTitle(title);
Blotter.setBusinessPayOrderId(businessPayOrderId);
Blotter.setTransactionAccount(transactionAccount);
Blotter.setStatus(status);
Blotter.setCompletionTime(new Date());
Blotter.setRemark(message);
Blotter.setServiceFee(serviceFee);
//关键信息
Blotter.setMchId(mchId);
Blotter.setCreatorId(user.getAccount());
Blotter.setCreatorName(user.getEmployeeName());
Map<String, Object> data = new HashMap<>();
if (isopenMQ) {
data.put("PayFundBlotter", Blotter);
// data.put("User",user);
activeManager.immediately(bloter_create, data);
} else {
getBaseDao().save(Blotter);
log.debug("流水明细。。。。。保存完毕");
}
}
下面这段代码是,传递一个对象给生产者。
bloter_create的值是pay.Fund.Blotter.create,通过springboot的@value值引用。
if (isopenMQ) {
data.put("PayFundBlotter", Blotter);
activeManager.immediately(bloter_create, data);
}
Producer(生产者)
接受传递过来的对象,并生产消息,将生产的消息通过队列发送给Consumer.
/**
* 即时发送 map数据到queue
* @desc
* @data map数据
*/
public void immediately(String dest,Map<String,Object> data) {
//获取连接工厂
ConnectionFactory connectionFactory = this.jmsMessagingTemplate.getConnectionFactory();
try {
//获取连接
Connection connection = connectionFactory.createConnection();
connection.start();
//获取session
Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
// 创建一个消息队列
Destination destination = session.createQueue(dest);
MessageProducer producer = session.createProducer(destination);
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
ObjectMessage message = session.createObjectMessage();
message.setObject((Serializable) data);
//发送
producer.send(message);
session.commit();
producer.close();
session.close();
connection.close();
} catch (Exception e) {
e.getMessage();
}
}
补充:JMS定义了五种消息类型,TextMessage、MapMessage、BytesMessage、
StreamMessage和ObjectMessage。比较常用的是TextMessage、MapMessage。
关于这5种消息类型的写法,在博客中有详细介绍。
Consumer(消费者)
这里的操作,只是将流水明细对象保存到数据库中。这里的activemq.queue_name.blotter_create值就是pay.Fund.Blotter.create
/*
* @Author ouyang
* @Description //流水明细保存
* @Date 18:16 2019/7/17
* @Param [message]
* @return void
**/
@JmsListener(destination = "${activemq.queue_name.blotter_create}")
public void sendBlotter(ObjectMessage message) throws Exception{
log.debug("成功监听pay.Fund.Blotter.create消息队列,当前时间为" + LocalDateTime.now());
Map<String,Object> data= (Map<String, Object>) message.getObject();
PayFundBlotter payFundBlotter=(PayFundBlotter) data.get("PayFundBlotter");
payFundBlotterDetailRepository.save(payFundBlotter);
log.debug("成功保存pay.Fund.Blotter.create消息队列,当前时间为" + LocalDateTime.now());
}
下面实际操作一下,当log.debug打出来说明该业务已经走通。
监控
ActiveMQ的监控,mq自带,属性自己配置。
总结
除了ActiveMq,还有其他Mq,如RabbitMq、 RocketMQ,在有详细介绍。
在这个业务中,对于ActiveMq的使用只是用于保存数据。常用的操作也有发送通知。此次调了一个比较简单的业务。