ActiveMQ概述

Apache ActiveMQApache软件基金会所研发的开放源码消息中间件;由于ActiveMQ是一个纯Java程序,因此只需要操作系统支持Java虚拟机,ActiveMQ便可执行。

特点: 
1、支持多种语言编写客户端 
2、对spring的支持,很容易和spring整合 
3、支持多种传输协议:TCP,SSL,NIO,UDP等 
4、支持AJAX 
消息形式: 
1、点对点(queue) 
2、一对多(topic)

ActiveMQ原理

ActiveMQ demo 码云 activemq原理_ObjectMessage

  1. 应用程序A和应用程序B运行于同一系统A,它们之间可以借助消息队列技术进行彼此的通讯;
  2. 应用程序A向队列1发送一条信息,而当应用程序B需要时就可以得到该信息。
  3. 其次是远程通讯的情况,如果信息传输的目标改为在系统B上的应用程序C,这种变化不会对应用程序A产生影响。
  4. 应用程序A向队列2发送一条信息,系统A的MQ发现Q2所指向的目的队列实际上位于系统B,它将信息放到本地的一个特殊队列-传输队列(Transmission Queue)。我们建立一条从系统A到系统B的消息通道,消息通道代理将从传输队列中读取消息,并传递这条信息到系统B,然后等待确认。只有MQ接到系统B成功收到信息的确认之后,它才从传输队列中真正将该信息删除。
  5. 如果通讯线路不通,或系统B不在运行,信息会留在传输队列中,直到被成功地传送到目的地。
  6. 这是MQ最基本而最重要的技术–确保信息传输,并且是一次且仅一次(once-and-only-once)的传递。MQ提供了用于应用集成的松耦合的连接方法,因为共享信息的应用不需要知道彼此物理位置(网络地址);不需要知道彼此间怎样建立通信;不需要同时处于运行状态;不需要在同样的操作系统或网络环境下运行。

ActiveMQ操作及企业实际运用

明白下面的各个角色的职责

  1. JMS框架基本角色和编程模块
  2. JMS Message Producers : 消息生产者,向消息队列提供消息
  3. JMS Provider(Broker) : JMS提供商,如ActiveMQ,提供JMS Queues/Topics服务
  4. JMS Message listener/Consumer :接收并使用消息

queue的使用

ActiveMQ demo 码云 activemq原理_JMS_02

导入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 demo 码云 activemq原理_JMS_03

ActiveMQ demo 码云 activemq原理_ObjectMessage_04

监控

ActiveMQ的监控,mq自带,属性自己配置。

ActiveMQ demo 码云 activemq原理_JMS_05

 

ActiveMQ demo 码云 activemq原理_JMS_06

ActiveMQ demo 码云 activemq原理_ActiveMQ demo 码云_07

总结

除了ActiveMq,还有其他Mq,如RabbitMq、 RocketMQ,在有详细介绍。

在这个业务中,对于ActiveMq的使用只是用于保存数据。常用的操作也有发送通知。此次调了一个比较简单的业务。