消息中间件解决方案JMS(转)

消息中间件解决方案JMS

1.JMS入门

1.1 消息中间件

消息中间件利用高效可靠的消息传递机制进行平台无关的数据交流,并基于数据通信来进行分布式系统的集成。通过提供消息传递和消息排队模型,它可以在分布式环境下扩展进程间的通信。对于消息中间件,常见的角色大致也就有Producer(生产者)、Consumer(消费者)

常见的消息中间件产品:

  • ActiveMQ

ActiveMQ 是Apache出品,最流行的,能力强劲的开源消息总线。ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的 JMS Provider实现。我们在本次课程中介绍 ActiveMQ的使用。

  • RabbitMQ

AMQP协议的领导实现,支持多种场景。淘宝的MySQL集群内部有使用它进行通讯,OpenStack开源云平台的通信组件,最先在金融行业得到运用。

  • ZeroMQ(已经式微)

史上最快的消息队列系统(由于配置相对复杂现在很少使用)

  • Kafka

Apache下的一个子项目 。特点:高吞吐,在一台普通的服务器上既可以达到10W/s的吞吐速率;完全的分布式系统。适合处理海量数据。

1.2 jms简介

1.2.1 什么是jms

JMS(JavaMessaging Service)是Java平台上有关面向消息中间件的技术规范,它便于消息系统中的Java应用程序进行消息交换,并且通过提供标准的产生、发送、接收消息的接口简化企业应用的开发。

JMS本身只定义了一系列的接口规范,是一种与厂商无关的 API,用来访问消息收发系统。它类似于 JDBC(javaDatabase Connectivity):这里,JDBC 是可以用来访问许多不同关系数据库的 API,而 JMS 则提供同样与厂商无关的访问方法,以访问消息收发服务。许多厂商目前都支持 JMS,包括 IBM 的 MQSeries、BEA的 Weblogic JMS service和 Progress 的 SonicMQ,这只是几个例子。 JMS 使您能够通过消息收发服务(有时称为消息中介程序或路由器)从一个 JMS 客户机向另一个 JML 客户机发送消息。消息是 JMS 中的一种类型对象,由两部分组成:报头和消息主体。报头由路由信息以及有关该消息的元数据组成。消息主体则携带着应用程序的数据或有效负载。

JMS 定义了五种不同的消息正文格式,以及调用的消息类型,允许你发送并接收以一些不同形式的数据,提供现有消息格式的一些级别的兼容性。

  • TextMessage--一个字符串对象

  • MapMessage--一套名称-值对

  • ObjectMessage--一个序列化的 Java 对象(重点掌握)

  • BytesMessage--一个字节的数据流

  • StreamMessage -- Java 原始值的数据流

1.2.1 JMS消息传递类型

  • 一种是点对点的,即一个生产者和一个消费者一一对应;

  • 另一种是发布/ 订阅模式,即一个生产者产生消息并进行发送后,可以由多个消费者进

行接收。

1.3 ActiveMQ下载与安装

  1. 将apache-activemq-5.12.0-bin.tar.gz 上传至服务器

  2. 解压此文件

  3. 进入bin目录执行启动语句

 ./activemq start

2.JMS入门小Demo

2.1 创建工程jmsDemo并引入依赖

<dependency>
    <groupId>org.apache.activemq</groupId>
    <artifactId>activemq-client</artifactId>
    <version>5.13.4</version>
</dependency>

2.2点对点模式

2.2.1 创建类QueueProducer

package com.zql.avtivemq;
​
import org.apache.activemq.ActiveMQConnectionFactory;
​
import javax.jms.*;
​
/**
 * @Author: zql
 * @Date: 2019/6/18 15:56
 * @Description: 点对点 消息生产者类
 */
public class QueueProducer {
    public static void main(String[] args) throws JMSException {
        //发送消息的9个步骤
        //1.创建连接工厂  本机ip为例
        ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.25.129:61616");
        //2.获取连接
        Connection connection = connectionFactory.createConnection();
        //3.启动连接
        connection.start();
        //4.获取session  (参数1:是否启动事务,参数2:消息确认模式)
        //AUTO_ACKNOWLEDGE = 1    自动确认
        //CLIENT_ACKNOWLEDGE = 2    客户端手动确认   
        //DUPS_OK_ACKNOWLEDGE = 3    自动批量确认
        //SESSION_TRANSACTED = 0    事务提交并确认
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        //5.创建队列对象
        Queue queue = session.createQueue("test-queue");
        //6.创建消息生产者对象或消费者
        MessageProducer producer = session.createProducer(queue);
        //7.创建消息                 //接受消息setMessageListener
        TextMessage message = session.createTextMessage("欢迎来到博客园");
        //8.使用生成者发送消息        //等待键盘输入System.in.read();
        producer.send(message);
        //9.关闭资源
        producer.close();
        session.close();
        connection.close();
    }
}

2.2.2 创建类QueueConsumer

package com.zql.activemq;
​
import org.apache.activemq.ActiveMQConnectionFactory;
​
import javax.jms.*;
import java.io.IOException;
​
/**
 * @Author: zql
 * @Date: 2019/6/18 15:56
 * @Description: 点对点 消息生产者类
 */
public class QueueConsumer {
    public static void main(String[] args) throws JMSException, IOException {
        //接收消息的9个步骤
        //1.创建连接工厂  本机ip为例
        ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.25.129:61616");
        //2.获取连接
        Connection connection = connectionFactory.createConnection();
        //3.启动连接
        connection.start();
        //4.获取session  (参数1:是否启动事务,参数2:消息确认模式)
        //AUTO_ACKNOWLEDGE = 1    自动确认
        //CLIENT_ACKNOWLEDGE = 2    客户端手动确认   
        //DUPS_OK_ACKNOWLEDGE = 3    自动批量确认
        //SESSION_TRANSACTED = 0    事务提交并确认
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        //5.创建队列对象
        Queue queue = session.createQueue("test-queue");
        //6.创建消息生产者对象或消费者
        MessageConsumer consumer = session.createConsumer(queue);
        //7.监听消息             //接受消息setMessageListener
        consumer.setMessageListener(new MessageListener() {
            @Override
            public void onMessage(Message message) {
                try {
                    TextMessage textMessage = (TextMessage) message;
                    System.out.println("接受到的信息为:" + textMessage.getText());
                } catch (JMSException e) {
                    e.printStackTrace();
                }
            }
        });
        //8.使用生成者发送消息  //等待键盘输入System.in.read();
        System.in.read();
        //9.关闭资源
        consumer.close();
        session.close();
        connection.close();
    }
}

 执行顺序

  producer--->consumer

执行结果
  接受到的信息为:欢迎来到博客园

2.3 发布/订阅模式

2.3.1 消息生产者

package com.zql.activemq;
​
import org.apache.activemq.ActiveMQConnectionFactory;
​
import javax.jms.*;
​
/**
 * @Author: zql
 * @Date: 2019/6/18 16:15
 * @Description: 发布/订阅模式  消息发布者
 */
public class TopicSenderTest {
    public static void main(String[] args) throws JMSException {
        //发送消息的9个步骤
        //1.创建连接工厂  本机ip为例
        ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.25.129:61616");
        //2.获取连接
        Connection connection = connectionFactory.createConnection();
        //3.启动连接
        connection.start();
        //4.获取session  (参数1:是否启动事务,参数2:消息确认模式)
        //AUTO_ACKNOWLEDGE = 1    自动确认
        //CLIENT_ACKNOWLEDGE = 2    客户端手动确认   
        //DUPS_OK_ACKNOWLEDGE = 3    自动批量确认
        //SESSION_TRANSACTED = 0    事务提交并确认
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        //5.创建队列对象
        Topic topic = session.createTopic("test-topic");
        //6.创建消息生产者对象或消费者
        MessageProducer producer = session.createProducer(topic);
        //7.创建消息
        MapMessage mapMessage = session.createMapMessage();
        mapMessage.setString("username", "cgx");
        mapMessage.setString("password", "123456");
        //8.使用生成者发送消息        //等待键盘输入System.in.read();
        producer.send(mapMessage);
        //9.关闭资源
        producer.close();
        session.close();
        connection.close();
    }
}

2.3.1 消息消费者

package com.zql.activemq;
​
import org.apache.activemq.ActiveMQConnectionFactory;
​
import javax.jms.*;
import java.io.IOException;
​
/**
 * @Author: zql
 * @Date: 2019/6/18 16:15
 * @Description: 发布/订阅模式  消息发布者
 */
public class TopicConsumerTest {
    public static void main(String[] args) throws JMSException, IOException {
        //发送消息的9个步骤
        //1.创建连接工厂  本机ip为例
        ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.25.129:61616");
        //2.获取连接
        Connection connection = connectionFactory.createConnection();
        //3.启动连接
        connection.start();
        //4.获取session  (参数1:是否启动事务,参数2:消息确认模式)
        //AUTO_ACKNOWLEDGE = 1    自动确认
        //CLIENT_ACKNOWLEDGE = 2    客户端手动确认   
        //DUPS_OK_ACKNOWLEDGE = 3    自动批量确认
        //SESSION_TRANSACTED = 0    事务提交并确认
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        //5.创建队列对象
        Topic topic = session.createTopic("test-topic");
        //6.创建消息生产者对象或消费者
        MessageConsumer consumer = session.createConsumer(topic);
        //7.监听消息                 //接受消息setMessageListener
        consumer.setMessageListener(new MessageListener() {
            @Override
            public void onMessage(Message message) {
                try {
                    MapMessage mess = (MapMessage) message;
                    System.out.println("===第1个监听===");
                    System.out.println("topic1接受的消息为:"+mess.getString("username"));
                    System.out.println("topic1接受的消息为:"+mess.getString("password"));
                } catch (JMSException e) {
                    e.printStackTrace();
                }
            }
        });
        //8.使用生成者发送消息        //等待键盘输入System.in.read();
        System.in.read();
        //9.关闭资源
        consumer.close();
        session.close();
        connection.close();
    }
}

执行顺序

consumer---->producer

执行结果

===第1个监听===
topic1接受的消息为:cgx
topic1接受的消息为:123456

3.spring整合jms

3.1 点对点模式

  • 创建工程springjms_producer,在POM文件中引入SpringJms 、activeMQ以及单元测试相关依赖

  • 在src/main/resources下创建spring配置文件applicationContext-jms-producer.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:amq="http://activemq.apache.org/schema/core"
       xmlns:jms="http://www.springframework.org/schema/jms"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/jms
        http://www.springframework.org/schema/jms/spring-jms.xsd">
    <!--包扫描-->
    <context:component-scan base-package="cn.zql.demo"></context:component-scan>

    <!-- 真正可以产生Connection的ConnectionFactory,由对应的 JMS服务厂商提供-->
    <bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
        <property name="brokerURL" value="tcp://192.168.25.129:61616"/>
    </bean>

    <!-- Spring用于管理真正的ConnectionFactory的ConnectionFactory -->
    <bean id="connectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory">
        <!-- 目标ConnectionFactory对应真实的可以产生JMS Connection的ConnectionFactory -->
        <property name="targetConnectionFactory" ref="targetConnectionFactory"/>
    </bean>

    <!-- Spring提供的JMS工具类,它可以进行消息发送、接收等 -->
    <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
        <!-- 这个connectionFactory对应的是我们定义的Spring提供的那个ConnectionFactory对象 -->
        <property name="connectionFactory" ref="connectionFactory"/>
    </bean>

    <!--这个是队列目的地,点对点的  文本信息-->
    <bean id="queueTextDestination" class="org.apache.activemq.command.ActiveMQQueue">
        <constructor-arg value="queue_text"/>
    </bean>

    <!--这个是订阅模式  文本信息-->
    <bean id="topicTextDestination" class="org.apache.activemq.command.ActiveMQTopic">
        <constructor-arg value="topic_text"/>
    </bean>
</beans>

3.1.1 创建queue消息生产者类

package cn.zql.demo;

import org.apache.activemq.command.ActiveMQQueue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.stereotype.Component;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;

/**
 * @Author: zql
 * @Date: 2019/6/18 16:52
 * @Description: 消息生产者类
 */
@Component
public class SpringQueueSend {

    @Autowired
    private JmsTemplate jmsTemplate;

    @Autowired
    private ActiveMQQueue queueTextDestination;

    /**
     * 功能描述: 发送消息
     *
     * @Date 2019/6/18 17:26
     * @Param [text] 消息内容
     * @return void
     */
    public void sendMessage(final String message){
        jmsTemplate.send(queueTextDestination, new MessageCreator() {
            public Message createMessage(Session session) throws JMSException {
                return session.createTextMessage(message);
            }
        });
    }
}

3.1.2 创建queueListener消息监听类

package cn.zql.demo;

import org.springframework.stereotype.Component;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

/**
 * @Author: zql
 * @Date: 2019/6/18 18:21
 * @Description:
 */
@Component
public class Queuelistner implements MessageListener {

    @Override
    public void onMessage(Message message) {
        try {
            TextMessage mess = (TextMessage) message;
            System.out.println("接受到的消息queue:"+mess.getText());
        } catch (JMSException e) {
            e.printStackTrace();
        }
    }
}

3.1.2 创建SpringRunner 加载配置文件 使监听器监听到消息生产者生产出来的数据

package cn.zql.demo;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.io.IOException;

/**
 * @Author: zql
 * @Date: 2019/6/18 19:51
 * @Description: 加载配置文件 使监听器监听到消息生产者生产出来的数据
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-activemq-consumer.xml")
public class SpringRunner {

    @Test
    public void Test() {
        try {
            System.in.read();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

3.1.3 点对点消费者的测试类

  • 创建配置文件 applicationContext-jms-consumer-queue.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:amq="http://activemq.apache.org/schema/core"
       xmlns:jms="http://www.springframework.org/schema/jms"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/jms
        http://www.springframework.org/schema/jms/spring-jms.xsd">

    <!-- 真正可以产生Connection的ConnectionFactory,由对应的 JMS服务厂商提供-->
    <bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
        <property name="brokerURL" value="tcp://192.168.25.129:61616"/>
    </bean>

    <!-- Spring用于管理真正的ConnectionFactory的ConnectionFactory -->
    <bean id="connectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory">
        <!-- 目标ConnectionFactory对应真实的可以产生JMS Connection的ConnectionFactory -->
        <property name="targetConnectionFactory" ref="targetConnectionFactory"/>
    </bean>

    <!--这个是队列目的地,点对点的  文本信息-->
    <bean id="queueTextDestination" class="org.apache.activemq.command.ActiveMQQueue">
        <constructor-arg value="queue_text"/>
    </bean>

    <!--这个是订阅模式  文本信息-->
    <bean id="topicTextDestination" class="org.apache.activemq.command.ActiveMQTopic">
        <constructor-arg value="topic_text"/>
    </bean>

    <!-- 我的监听类 -->
    <bean id="myMessageListener" class="cn.zql.demo.Queuelistner"></bean>

    <bean id="topListener" class="cn.zql.demo.TopicListen"></bean>
    <!-- 消息监听容器 -->
    <bean class="org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="connectionFactory" ref="connectionFactory" />
        <property name="destination" ref="queueTextDestination" />
        <property name="messageListener" ref="myMessageListener" />
    </bean>

    <!-- 消息监听容器-->
    <bean class="org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="connectionFactory" ref="connectionFactory" />
        <property name="destination" ref="topicTextDestination" />
        <property name="messageListener" ref="topListener" />
    </bean>

</beans>
  • 点对点测试类

package cn.zql.demo;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**
 * @Author: zql
 * @Date: 2019/6/18 17:51
 * @Description: 消息生产者测试类
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-activemq-producer.xml")
public class SpringSendQueueTest {

    @Autowired
    private SpringQueueSend queueProducer;
    
    @Test
    public void testQueueSend(){
        for (int i = 0; i < 5; i++) {
            queueProducer.sendMessage("通过jmsTemplate发送queue消息,第"+i);
        }
    }
}

执行顺序

SpringSendTest(先生产)---->SpringRunner(再监听消息并消费)

queueListener执行结果为:

接受到的消息queue:通过jmsTemplate发送queue消息,第0
接受到的消息queue:通过jmsTemplate发送queue消息,第1
接受到的消息queue:通过jmsTemplate发送queue消息,第2
接受到的消息queue:通过jmsTemplate发送queue消息,第3
接受到的消息queue:通过jmsTemplate发送queue消息,第4

3.2 发布/订阅模式

3.2.1 topic消息生产者

package cn.zql.demo;

import org.apache.activemq.command.ActiveMQTopic;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.stereotype.Component;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;

/**
 * @Author: zql
 * @Date: 2019/6/18 20:02
 * @Description: 发布/订阅模式的消息生产者
 */
@Component
public class SpringTopicSend {

    @Autowired
    private JmsTemplate jmsTemplate;

    @Autowired
    private ActiveMQTopic topicTextDestination;

    public void sendMessage(final String text) {
        jmsTemplate.send(topicTextDestination, new MessageCreator() {
            @Override
            public Message createMessage(Session session) throws JMSException {
                return session.createTextMessage(text);
            }
        });
    }
}

3.2.2 topic监听器

package cn.zql.demo;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

/**
 * @Author: zql
 * @Date: 2019/6/18 20:25
 * @Description: topic模式的消息监听类
 */

public class TopicListen implements MessageListener {

    @Override
    public void onMessage(Message message) {
        try {
            TextMessage mess = (TextMessage) message;
            System.out.println("接受到的消息topic:"+mess.getText());
        } catch (JMSException e) {
            e.printStackTrace();
        }
    }
}

3.2.3 topic测试类

package cn.zql.demo;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**
 * @Author: zql
 * @Date: 2019/6/18 17:51
 * @Description: 消息生产者测试类
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-activemq-producer.xml")
public class SpringSendTopicTest {
    
    @Autowired
    private SpringTopicSend topicProducer;

    @Test
    public void testTopicSend(){
        for (int i = 0; i < 5; i++) {
            topicProducer.sendMessage("通过jmsTemplate发送topic消息,第"+i);
        }
    }
}

执行顺序

SpringRunner ---->SpringSendTest

执行结果

接受到的消息topic:通过jmsTemplate发送topic消息,第0
接受到的消息topic:通过jmsTemplate发送topic消息,第1
接受到的消息topic:通过jmsTemplate发送topic消息,第2
接受到的消息topic:通过jmsTemplate发送topic消息,第3
接受到的消息topic:通过jmsTemplate发送topic1消息,第4

猜你喜欢

转载自www.cnblogs.com/ryouji/p/11048916.html