ActiveMQ_windows导读_C_2021-03-04

写在前头,ActiveMQ开头的几篇博客都是基于windows环境去写,大家更熟悉windows环境。等把该讲的都讲完了,在换到linux系统上去。

序号说明
C_2021-03-04第一次编写
U_2021-03-05更新了持久化、协议的内容,并关联链接
U_2021-03-06增加了关于ActiveMQ的基础操作
U_2021-03-12增加了基础API详解
U_2021-03-15增加了ActiveMQ消息发送的知识

文档说明

这边博客会基于Windows环境下,对ActiveMQ进行讲解,并且在后续编写ActiveMQ的博客时,将对应的例子引入到这边博客中。因此,这篇博客可以认为是基于windows环境下,对ActiveMQ(不涉及集群)的一篇导读。
举个例子,假设在下面的ActiveMQ配置子章节里,讲到了死信的配置信息。但是作为第一篇讲ActiveMQ的博客,我精力不够一次性写到死信,到时候会把简单的配置写好,然后扔一个跳转到高阶应用的地址。基于这种概述和链接的组合模式,构成了这篇windows下的导读。
后续写到集群时,会迁移至linux系统进行演示。

初识ActiveMQ

在windows环境下安装和启动ActiveMQ

ActiveMQ官网中提供了ActiveMQ的下载选项,下载windows系统对应的压缩包,之后进行解压,解压后文件夹内如下:
文件解压后示例

  • bin
    bin文件夹里面是对应的bat脚本,分为32位和64位。
  • conf
    conf文件夹里是配置文件。
  • data
    不论是windows还是linux系统,ActiveMQ在使用默认的持久化机制(kahadb)时,对应的文件会存在data文件夹里。
  • docs
    文档
  • examples
    examples文件夹里包罗了各式各样的例子。
  • lib
    jar包
  • webapps&webapps-demo
    ActiveMQ web控制台

ActiveMQ是一个解压就可以直接使用的程序。解压完成后,双击32位或者64位中对应的 activemq.bat 进行启动。

基础配置

conf文件夹内容解压后的conf文件夹内容如上所示,其中 jetty.xml是web控制台的配置, activemq.xml则是ActiveMQ的配置文件,其余各式各样的资源文件被配置文件引用了。其他的文档我并没关注什么。

Web控制台配置

  1. 控制台端口
    端口号最常用的第一个配置,web控制台的主机地址和端口号,在配置文件的117行。

  2. 账户密码
    账户密码在配置文件一开始,引入了 jetty-realm.properties文件,这里面是web控制台的账户密码。web控制台打开需要身份验证。账号密码就在这个资源文件里面改。

ActiveMQ配置

ActiveMQ的配置文件是activemq.xml,下面讲解的内容都是基于这个文件进行描述。

持久化

ACtimeMQ提供了多种持久化策略,参见持久化策略概述。
在配置ActiveMQ的持久化策略时,是在broker标签下的persistenceAdaptor中。

协议

ActiveMQ支持多种传输协议,查看完整协议,请点击链接。下面会单独挑选出几个进行简单讲解和配置,ActiveMQ常见协议概述。
在配置ActiveMQ的传输协议时,是在broker标签下的transportConnectors

空间大小

broker标签下,有一个systemUsage标签,里面标注了当前broker对应的物理空间,配置如下。

<systemUsage>
    <systemUsage>
        <memoryUsage>
        	<!--Java虚拟机可用内存百分比-->
            <memoryUsage percentOfJvmHeap="70" />
        </memoryUsage>
        <storeUsage>
        	<!--当前broker最大存储空间-->
        	<!--即使服务器对物理空间实现了热插拔,但是broker只会之别在启动时,设备提供的可用大小-->
            <storeUsage limit="100 gb"/>
        </storeUsage>
        <tempUsage>
            <!--当最大存储空间用完了之后,会启用这部分临时空间-->
            <tempUsage limit="50 gb"/>
        </tempUsage>
    </systemUsage>
</systemUsage>
其他

这部分内容,随着使用在逐步往里加。

hello activemq

这个子章节里会讲解ActiveMQ最基本的代码,并且根据这个demo解释一些ActiveMQ中的角色。

角色

  • broker:消息服务器,作为server提供消息核心服务
  • provider:消息的生产者,由会话创建的一个对象,用于把消息发送到一个目的地(destination)
  • consumer:消息的消费者,由会话创建的一个对象,用于从消息从目的地(destination)提取出来。
    提取消息的方法由两种,一种同步阻塞,一种异步不阻塞。
    同步阻塞:consumer的receive方法。在调用这个方法后,线程会一直阻塞直到收到消息。
    异步方法:通过consumer的messageListener接口,重写了onMessage方法。当有消息被提取的时候,会自动回调这个onMessage方法。
  • p2p:点对点的传播方式,Queue。
    消息生产者生产消息后发送到Queue(destination的子类)中,之后消息消费者再从Queue中去提取消息。Queue中的消息一旦被一个消费者消费后,Queue就不在存储这个消息。Queue支持多个消费者,但是对一个消息而言,只会有一个消费者可以消费,其他的消费者不能再消费这个消息。当消费者不存在的时候,消息会持续存在,直到有消费者(前提是消息没有过期)。
  • pub/sub:发布订阅的形式,Topic。
    消息生产者生产消息后发送到Topic(destination的子类)中,broker会一次性把消息推送给所有的consumer。除了这点不同之外,在Topic下,不论是否有消费者去提取消息,broker都不会类似Queue这样保留消息等候消费者去提取,也就是说,在Topic中,如果消息生产后没有消费者去消费,当有新的消费者来了之后,也无法从Topic取到这个消息(持续订阅除外)。
  • connectionFactory:连接工厂,JMS中用它创建连接。因为ActiveMQ满足JMS规范,所以ActiveMQ也是通过ConnectionFactory创建连接。
  • Connection:连接,JMS Connection封装了用户与JMS提供者(供应商)之间的一个虚拟连接。
  • Destination:目的地,更直观的就是队列的名称,再具体些,就是在实例化Queue或者Topic的时候给定的名称。在点对点传输中,destination被称为queue,在发布订阅中,被称为topic。
  • session:JMS Session,会话,是生产与消费消息的一个单线程上下文。
    Session(会话) 用于创建provider(消息生产者)、consumer(消息消费者)、message(消息)、Queue(消息队列)和Topic(发布订阅)。
    Session(会话)提供了一个事务性的上下文,在这个上下文中,一组发送和接收操作组合到一个原子操作中。

步骤

在使用ActiveMQ的时候与使用JDBC非常类似,都是有固定步骤的。

  1. 创建连接工厂 ConnectionFactory
  2. 创建连接 Connection
  3. 开启连接 Connection.start()
    注意,如果是provider(生产者)端,不开启连接并不影响使用,但是在consumer(消费者)端,不开启连接会影响后面的使用。
  4. 创建会话
  5. 用Session创建Destination,在创建destination的时候,实际就是创建Queue或者Topic。

创建Session和Destination完成之后,需要根据自己的场景有两处细分。
如果是provider端:

  1. 创建完成Destination之后,在用Session创建provider,此时需要把刚才创建的destination作为参数。
  2. 用Session创建Message。Message有很多具体的类型来简化我们的操作,比如,TextMessage就是用来传递String类型的信息。
  3. 用provider发送Message到ActiveMQ。

如果是consumer端:

  1. 用Session创建consumer,此时需要把刚才创建的Destination作为参数。
  2. 用创建好的Consumer从ActiveMQ中提取消息(Message)。这里就会出现在上面介绍Consumer时提到的,提取消息有两种方法,分别是同步阻塞和异步不阻塞两种方式。

最后,不论是consumer或者是provider,当不再需要的时候,还需要关闭连接。

代码

代码示例采用了Queue这种形式编写。
代码结构如下所示,是一个简单的springboot项目。这里使用Springboot,只是为了方便启动。在创建Springboot时,选择了Web和ActiveMQ5这两个Starter。之所以选择Web是为了方便演示。
注意,这个项目并没有演示Springboot整合ActiveMQ,所以在application.properties中没有写任何有关于ActiveMQ的配置信息,它是个空的。
项目结构Controller代码如下,在Controller中提供了一个方法send。在send方法中,调用了发送和收取两个方法。其实,接收的方法没必要写在这里被调用,因为我这边实现Consumer提取消息的时候,使用的是异步回调的形式,而非单次同步阻塞的方式。写在这里,纯粹是为了降低读代码的难度。

package com.phl.spring_active_mq.simpledemo.controller;

import com.phl.spring_active_mq.simpledemo.service.ReceiveService;
import com.phl.spring_active_mq.simpledemo.service.SendService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.jms.JMSException;

/**
 * 在simple demo 包里面,做了一个基于web演示的ActiveMQ demo。
 * 在这个demo中,并不是继承springboot+ActiveMQ,只是单纯的使用ActiveMQ,springboot只是作为一个启动容器存在。
 *
 */
@RestController
public class MainTest {

    @Autowired
    SendService sendService;

    @Autowired
    ReceiveService receiveService;

    /**
     * 这个方法中,给destination中发送信息msg
     * @param destination 目的地
     * @param msg 消息
     * @return
     */
    @RequestMapping("/send/{destination}/{msg}")
    public String send(@PathVariable("destination") String destination, @PathVariable("msg") String msg) throws JMSException {
        sendService.sendQueue(destination,msg);
        receiveService.receiveQueue(destination);
        return "OK";
    }

}

工具类Util代码如下,在Util中,完成了上述讲解步骤中的内容,封装了对应的方法中,便于理解。
在这个例子中,除了实例化连接工厂的时候需要提供一个具体的实现类之外,其他地方如Connection,Provider,Consumer,Session等都是使用 javax.jms包里的接口。强调只是为了再次提醒,因为ActiveMQ满足JMS规范(其实就是实现了JMS提供的接口)所以可以粗放地使用这些接口。其实,对于ActiveMQ而言,全都使用ActiveMQ提供的对象的话更好,它提供了JMS中没提供的一些方法。

package com.phl.spring_active_mq.simpledemo.util;

import org.apache.activemq.ActiveMQConnectionFactory;
import org.springframework.stereotype.Component;

import javax.jms.*;

@Component
public class ConnectionUtil {
    static String brokerUrl = "tcp://localhost:61616";

    private Connection queueConnection;

    private Session session;

    {
        /*
         * ActiveMQ在使用的过程中,非常类似使用JDBC,同样存在固定的顺序。
         */
        // 创建连接工厂 ConnectionFactory
        ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(brokerUrl);
        // 创建连接  Connection
        try {
            this.queueConnection = connectionFactory.createConnection();

        } catch (JMSException e) {
            e.printStackTrace();
        }
        // 开启连接
        // 注意,这个connection在使用的时候,如果是provider端,不去start也可以正常使用。
        // 但是,在consumer端,不进行start,不能正常使用。
        try {
            this.queueConnection.start();
        } catch (JMSException e) {
            e.printStackTrace();
        }
        // 创建会话
        try {
            this.session = this.queueConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        } catch (JMSException e) {
            e.printStackTrace();
        }
    }

    /**
     * 返回 session
     * @return
     */
    public Session getSession() {
        return this.session;
    }

    /**
     * 创建Queue
     * @param destination
     * @return
     * @throws JMSException
     */
    public Queue getQueue(String destination) throws JMSException {
        Queue queue = this.getSession().createQueue(destination);
        return queue;
    }

    /**
     * 创建生产者
     * @param destination
     * @return
     * @throws JMSException
     */
    public MessageProducer getProducer(String destination) throws JMSException {
        return this.getSession().createProducer(this.getQueue(destination));
    }

    /**
     * 创建消费者
     * @param destination
     * @return
     * @throws JMSException
     */
    public MessageConsumer getConsumer(String destination) throws JMSException {
        return this.getSession().createConsumer(this.getQueue(destination));
    }

	public void stop() throws JMSException {
        this.session.close();
        this.queueConnection.stop();
    }
    
}


下面就分别是provider和consumer的代码。
Provider端:

package com.phl.spring_active_mq.simpledemo.service;

import com.phl.spring_active_mq.simpledemo.util.ConnectionUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;

@Service
public class SendService {
    @Autowired
    ConnectionUtil util;

    /**
     * 发送信息到ActiveMQ
     * @param destination
     * @param msg
     * @throws JMSException
     */
    public void sendQueue(String destination, String msg) throws JMSException {
        Session session = util.getSession();
        MessageProducer producer = this.util.getProducer(destination);
        TextMessage textMessage = session.createTextMessage(msg);
        producer.send(textMessage);
    }
}

Consumer端:

package com.phl.spring_active_mq.simpledemo.service;

import com.phl.spring_active_mq.simpledemo.util.ConnectionUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.jms.*;

@Service
public class ReceiveService {
    @Autowired
    ConnectionUtil util;


    public void receiveQueue(String destination) throws JMSException {
        MessageConsumer consumer = this.util.getConsumer(destination);
        /**
         * 得到consumer之后,有两种方法去消费 ActiveMQ 中的信息。
         * 方法一:
         *  consumer.receive();
         *  这个方法在从 ActiveMQ 收到消息之前,会在这里阻塞住,在实际生产中使用并不多。
         * 方法二:
         * 创建一个messageListener,当有消息过来之后,会回调listener中的onMessage方法。
         * 在 Java8 及更高版本中,下面的代码可以简化成lambda表达式,但是这个表达式太简洁,不利于不熟悉的人读代码。
         */
        consumer.setMessageListener(new MessageListener() {
            @Override
            public void onMessage(Message message) {
                try {
                    String msg = ((TextMessage) message).getText();
                    System.out.println("ActiveMQ 中取出来的数据是 :: " + msg);
                } catch (JMSException e) {
                    e.printStackTrace();
                }
            }
        });
    }

}

运行结果

上面是所有的代码,下面结合着ActiveMQ的web控制台进行结果演示。
web控制台上图就是在ActiveMQ启动后,它提供的web控制台。控制台的账户密码在上面讲配置的时候讲到了。进入web控制台之后,点击“manage ActiveMQ broker”,进入管理页面。
管理页面进来之后根据自己的需要选择Queue或者Topic进入相应页面。
Queue初始页面之后,启动springboot项目,在浏览器中访问send方法。因为Controller中已经设置了,url倒数第二位是Destination的名字,最后以为是msg的内容,因此当我们访问之后,在之前的外部控制台就能看到对应信息,同时,在IDEA的consolo中我也做了对应的输出。
控制台输出控制台监控详解多刷新几次页面后,发现这个情况:
新consumer的个数增加了。那是因为例子里没有关闭连接,并且consumer在send方法里进行了实例化所致。

基础API详解

在上面的例子中,已经做了一个基于Queue的简单应用。现在,会基于上面的例子,将常用API进行讲解和测试。基础API讲解&一些对象解释。

消息发送

关于消息发送的内容已经完成编写,ActiveMQ_消息发送。

一些高级应用和高级场景

内容正在编写, 请稍后

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值