ActiveMQ

ActiveMQ官网:https://activemq.apache.org/

1、ActiveMQ在Linux下安装

1.1、上传到/opt目录下

1.2、解压缩 tar -zxvf 包名

1.3、在根目录下创建文件夹 mkdir /myactiveMQ

1.4、cp -r apache-activemq-5.15.9 /myactiveMQ/

1.5、启动activemq ./activemq start

1.6、查看activemq是否启动,activemq的默认进程端口是61616 ps -ef|grep activemq -v grep

1.7、带日志的启动:./activemq start > /myactiveMQ/run_cativemq.log

1.8、关闭activemq ./activemq stop

2、ActiveMQ控制台

控制台访问:http://Linux的IP地址:8161/admin/

默认的用户名和密码都是admin、admin

3、ActiveMQ通讯

3.1、导入依赖

复制代码
<dependency>
    <groupId>org.apache.activemq</groupId>
    <artifactId>activemq-all</artifactId>
    <version>5.10.1</version>
</dependency>
<dependency>
    <groupId>org.apache.xbean</groupId>
    <artifactId>xbean-spring</artifactId>
    <version>4.18</version>
</dependency>
复制代码

 

3.2、编码总体框架

  

 

3.3、队列queue

在点对点的消息传递域中,目的地被称为队列。

消息生产者

复制代码
public class JmsProduce{
      public static final String ACTIVEMQ_URL = "tcp://192.168.111.136:61616";
      public static final QUEUE_NAME = "queue01"
      public static void main(String[] args)throws JMSException{
          //1、创建连接工厂,采用默认用户名和密码
          ActiveMQConnectionFactory am = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
          //2、通过连接工厂,获得连接connection
          Connection conn = am.createConnection();
          conn.start();
          //3.创建回话session,第一个叫事务,第二个叫签收
          Session session = conn.createSisson(false,Session.AUTO_QCKNOWLEDG);
          //4 创建目的地
          Queue queue = session.createQueue(QUEUE_NAME);
          //5 创建消息的生产者
          MessageProducer mess = session.createProducer(queue);
          for(int i = 0; i<=3;i++){
          //7创建消息
          TextMessage textMessage = session.createTextMessage("msg---"+i);//理解为一个字符串
          //8 通过messageproducer发送msg
          mess.send(textMessage);
          }
          //9 关闭资源
          mess.close();
          session.close();
          connection.close();
          
          System.out.println("发送成功");
          
      }
}
复制代码

 消息消费者

复制代码
public class JmsConsumer{
      public static final String ACTIVEMQ_URL = "tcp://192.168.111.136:61616";
      public static final QUEUE_NAME = "queue01"
      
      public static void main(String[] args)throws JMSException{
          //1、创建连接工厂,采用默认用户名和密码
          ActiveMQConnectionFactory am = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
          //2、通过连接工厂,获得连接connection
          Connection conn = am.createConnection();
          conn.start();
          //3.创建回话session,第一个叫事务,第二个叫签收
          Session session = conn.createSisson(false,Session.AUTO_QCKNOWLEDG);
          //4 创建目的地
          Queue queue = session.createQueue(QUEUE_NAME);
          //5 创建消费者
          MessageProducer mess = session.createConsumer(queue);
          /**
          同步阻塞方式
          订阅者或接受者调用messageconsumer的receive()方法来接收消息,receive方法在能够接收到消息之前(或超时之前)将一直阻塞。
          
          while(true){
          TextMessage message =(TextMessage) mess.receive();
          if(message!=null){
          System.out.println("消费者接收到信息"+message.getText())
          }else{
          break;
          }
          }
          mess.close();
          session.close();
          connection.close();
          */
          
 }      
}
复制代码

 

3.5、消费者消费情况

  1. 先生产,然后启动一号消费者,1号消费者消费了消息,在启动二号消费者,二号消费者消费不到消息。

  2. 先启动2个消费者,再生产6个消息,这样的情况下,消费情况是平均分配(轮询)。

3.6、主题Topic(一对多)

生产者将消息发布到topic中,每个消息可以有多个消费者,属于1:N关系

生产者和消费者之间有时间上的相关性,订阅某一个主题的消费者只能消费自它订阅之后发布的消息

生产者生产时,topic不保存消息他是无状态的不落地,加入无人订阅就去生产,那就一条废消息,所以,一般先启动消费者在启动生产者。

消息生产者:

复制代码
public class JmsProduce{
      public static final String ACTIVEMQ_URL = "tcp://192.168.111.136:61616";
      public static final TOPIC_NAME = "topic01"
      public static void main(String[] args)throws JMSException{
          //1、创建连接工厂,采用默认用户名和密码
          ActiveMQConnectionFactory am = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
          //2、通过连接工厂,获得连接connection
          Connection conn = am.createConnection();
          conn.start();
          //3.创建回话session,第一个叫事务,第二个叫签收
          Session session = conn.createSisson(false,Session.AUTO_QCKNOWLEDG);
          //4 创建目的地
          Topic topic = session.createTopic(TOPIC_NAME);
          //5 创建消息的生产者
          MessageProducer mess = session.createProducer(topic);
          for(int i = 0; i<=3;i++){
          //7创建消息
          TextMessage textMessage = session.createTextMessage("msg---"+i);//理解为一个字符串
          //8 通过messageproducer发送msg
          mess.send(textMessage);
          }
          //9 关闭资源
          mess.close();
          session.close();
          connection.close();
          
          System.out.println("发送成功");
          
      }
}
复制代码

消息消费者

复制代码
public class JmsConsumer{
      public static final String ACTIVEMQ_URL = "tcp://192.168.111.136:61616";
      public static final TOPIC_NAME = "topic01"
      
      public static void main(String[] args)throws JMSException{
          //1、创建连接工厂,采用默认用户名和密码
          ActiveMQConnectionFactory am = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
          //2、通过连接工厂,获得连接connection
          Connection conn = am.createConnection();
          conn.start();
          //3.创建回话session,第一个叫事务,第二个叫签收
          Session session = conn.createSisson(false,Session.AUTO_QCKNOWLEDG);
          //4 创建目的地
          Topic topic = session.createTopic(TOPIC_NAME);
          //5 创建消费者
          MessageConsumer mess = session.createConsumer(topic);
          
          
          //通过监听的方式来消费消息
         
          messConsumer.setMessageLister(( message)->{
           if(null !=message && message instanceof TextMessage){
             TextMessage textMessage = (TextMessage)message;
             try{
             System .out.println("消费者接收到消息"+textMessage.getText());
             }catch(JMSException e){
             e.printStackTrace();
             }
             }
          })
          System.in.read();
          mess.close();
          session.close();
          connection.close();
 }      
}
复制代码

4、JMS

4.1、JMS是什么

两个应用程序之间的异步通信API。

4.2、JMS的组成结构

 

JMS provider:实现JMS接口个规范的消息中间件,也就是我们的MQ服务器

JMS producer:消息生产者,创建个发送JMS消息的客户端应用

JMS consumer:消息消费者,接受和处理JMS消息的客户端应用

JMS message:

  • 消息头:

    . JMSDestination 消息发送的⽬的地(队列或主题);创建消息时可以设置JMSDestination,但是在发送完成时其值会更新为发送⽅所指定的 JMSDestination,也就是说发送前该字段会被忽略;当消息被消费时,该字段的值与在它被发送时(send⽅法)被设置的值是相同的

    JMSDeliveryMode:持久模式和非持久模式,默认是持久的

    一条持久性的消息,:应该被传送”一次仅仅一次“,这就意味着如果JMS提供者出现故障,该消息并不会丢失,他会在服务器恢复之后再次传递。

    一条非持久的消息:最多会传送一次,这就意味着服务器出现故障,该消息将永远丢失。

    JMSExpriation:消息的过期时间,默认的永不过期

    JMSPriority:消息的优先级,从0-9级别,0-4是普通消息,5-9是加急消息,默认是4级

    JMSMessageID:唯一识别每个消息的编号

  • 消息体:

    封装具体的消息数据

    5种消息体格式:

    TextMessage:普通的字符串消息,包含⼀个String

    MapMessage:Map类型的消息,Key为String类型,值为java基本类型

    BytesMessage:二进制数组消息,包含一个byte[]

    StreamMessage:java数据流消息,用标准流操作来顺序的填充和读取

    ObjectMessage:对象消息,包含一个可序列化的Java对象

    发送和接受的消息体类型必须一致对应

  • 消息属性:

    如果需要除消息头字段以外的值,那么可以使用消息属性。

    识别/去重/重点标注等操作非常有用的方法。

    消息属性是什么?

    如果需要去除消息头字段以外的值,那么可以使用消息属性,消息属性是以属性名和属性值对的形式制定的,可以将属性视为消息头的扩展,属性指定一些消息头没有包括的附加信息,比如可以在属性里指定消息选择器。消息的树形就像可以分配给一条消息的附加消息头一样。它们允许开发者添加有关消息的不透明附加消息。

TextMessage textMessage = session.createTextMessage("msg---"+i);
textMessage.setStringProperty("co1","vip");

消费者

textMessage.getStringProperty("co1");

4.3、JMS可靠性

4.3.1、Persistent:持久性

  • 参数说明:

    • 非持久:

      • messageProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT)

      • 非持久化:当服务器宕机,消息不存在

    • 持久:

      • messageProducer.setDeliveryMode(DeliveryMode.PERSISTENT)

      • 持久化:当服务器宕机,消息依然存在

  • 持久的Queue:

    队列的默认是持久化的,此模式保证这些消息只被传送一次和成功使用一次,对于这些消息,可靠性是优先考虑的因素。

    可靠性的另一个方面是确保持久性消息传送至目标后,消息服务再向消费者传送他们之前不会丢失这些消息。

  • 持久的Topic:

    • 一定要先运行一次消费者,等于向MQ注册,类似我订阅这个主题

    • 然后再运行生产者发送信息,此时,无论消费者是否在线,都会接收到,不在线的话,下次连接的时候,会把没有收到的消息都接收下来。

4.3.2、transaction:事务

//3.创建回话session,第一个叫事务,第二个叫签收
Session session = conn.createSisson(true/false,Session.AUTO_QCKNOWLEDG);

生产者在提交事务的时候有两个选项,分别是true和false

false:

  • 只要执行send,就进入到队列中

  • 关闭事务,那第2个签收参数的设置需要有效

true:

  • 先执行send在执行commit,消息才被真正的提交到队列中

    需要在关闭资源的时候编写:session.commit();

  • 消息需要批量,需要缓冲区处理

4.3.3、Acknowledge:签收

非事务

  • 手动签收:session.CLIENT_ANKNOWLEDGE

Session session = conn.createSisson(false,Session.CLIENT_QCKNOWLEDG);
  • 客户端调用acknowledge方法手动签收 :message.acknowledge();

  • 自动签收(默认):session.AUTO_ANKNOWLEDGE

事务

  • 手动签收

    复制代码
    Session session = conn.createSisson(true,Session.CLIENT_QCKNOWLEDG);
    while(true){
        TextMessage textMessage = (TextMessage)messageConsumer.receive(4000L);
        if(textMessage != null){
        System.out.println("消费者接收到消息"+textMessage.getText());
            textMessage.acknowledge;
        }else{
        break;
        }
    }
    session.commit();
    复制代码

     

签收和事务关系

  • 在事务性回话中,当一个事务被成功提交则消息自动签收,如果事务回滚,则消息会被再次传送

  • 非事务性会话中,消息何时被确认取决于创建会话时的应答模式(acknowledgement mode)

5、ActiveMQ的Broker

相当于一个ActiveMQ服务器实例。

实现了代码的形式启动ActiveMQ将MQ嵌入到Java中,以便随时用随时启动,在用的时候再去启动这样能节省资源,也保证了可靠性。

5.1、嵌入式Borker

pom.xml

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.2.2</version>
</dependency>


EmbedBroker

复制代码
public class EmbedBroker
{
    public static void main(String[] args)throws Exception
    {
    //ActiveMQ也支持在vm中通信基于嵌入式的Broker
    BrokerService brokerService = new BrokerService();
    brokerService.setUseJmx(true);
    brokerService.addConnector("tcp://localhost:61616");
    brokerService.start();
    }
}
复制代码

6、SpringBoot整合ActiveMQ

6.1、队列

6.1.1、生产者

  1. 新建工程

  2. pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-activemq</artifactId>
    <version>2.6.7</version>
</dependency>

application.yml

复制代码
server.port:7777

spring.activemq.broker-url=tcp://193.168.111.136:61616 #MQ服务器地址
spring.activemq.user=admin
spring.activemq.password=admin
spring.jms.pub-sub-domain=false  #false = queue   true = topic 不写默认就是false

#自己定义队列名称
myqueue=boot-activemq-queue
复制代码

配置Bean

复制代码
@Component
@EnableJms
public class ConfigBean {
    @Value("${myQueue}")
    private String Queue;

    @Bean
    public javax.jms.Queue queue()
    {
        return new ActiveMQQueue(Queue);
    }
}
复制代码

Queue_Producer

复制代码
@Component
public class Queue_Producer {
    @Autowired
    private JmsMessagingTemplate jmsMessagingTemplate;

    @Autowired
    private Queue queue;

    public void produceMsg(){
        jmsMessagingTemplate.convertAndSend(queue,"******:"+ UUID.randomUUID().toString().substring(0,6));
    }
}
复制代码

主启动类MainApp_Produce

测试单元

复制代码
@SpringBootTest("classes = MainApp_Produce.class")
@Runwith(SpringJunit4ClassRunner.class)
@WebAppConfiguration
public class TestActiveMQ
{
    @Resource
    private Queue_Producer queue_producer;
    
    public void testSend()throws Exception{
          queue_producer.produceMsg();
    }
}
复制代码

 

每3秒往MQ推送消息,以下定时发送case:

定时投递:

复制代码
@Component
public class Queue_Producer {
    @Autowired
    private JmsMessagingTemplate jmsMessagingTemplate;

    @Autowired
    private Queue queue;

    public void produceMsg(){
        jmsMessagingTemplate.convertAndSend(queue,"******:"+ UUID.randomUUID().toString().substring(0,6));
    }
    //间隔3秒钟定投
    @Scheduled(fixedDelay = 3000)
    public void produceMsgScheduled(){
        jmsMessagingTemplate.convertAndSend(queue,"定时投放******:"+ UUID.randomUUID().toString().substring(0,6));
    }
}
复制代码

主启动类上需要添加@EnableScheduling注解

队列消费者

pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-activemq</artifactId>
    <version>2.6.7</version>
</dependency>

application.yml

复制代码
server.port:8888

spring.activemq.broker-url=tcp://193.168.111.136:61616 #MQ服务器地址
spring.activemq.user=admin
spring.activemq.password=admin
spring.jms.pub-sub-domain=false  #false = queue   true = topic 不写默认就是false

#自己定义队列名称
myqueue=boot-activemq-queue
复制代码

Queue_Consumer

@Component
public class Queue_Consumer{
      @JMSListener(destination = "${myqueue}")
      public void receive(TextMessage textMessage)throws JMSException{
          System.out.pritln("消费者收到消息"+textMessage.getText);
          
      }
}

6.2、发布订阅

6.2.1、Topci生产者

application.yml

复制代码
server.port:6666

spring.activemq.broker-url=tcp://193.168.111.136:61616 #MQ服务器地址
spring.activemq.user=admin
spring.activemq.password=admin
spring.jms.pub-sub-domain=true  #false = queue   true = topic 不写默认就是false

#自己定义队列名称
myTopic=boot-activemq-topic
复制代码

配置Bean

 

Topic_Producer

主启动类

 

消费者

application.yml

分别用2个不同的端口模仿不同的用户

 

posted @   暮商  阅读(278)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示