消息中间件--ActiveMQ

一、消息中间件(Message-Oriented)

1.1 什么是消息中间件

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

1.2 为什么要用消息中间件

主要原因是由于在高并发环境下,由于来不及同步处理,请求往往会发生堵塞,比如说,大量的insert,update之类的请求同时到达MySQL,直接导致无数的行锁表锁,甚至最后请求会堆积过多,从而触发too many connections错误。通过使用消息队列,我们可以异步处理请求,从而缓解系统的压力。

1.3 常见的消息中间件产品

  • ActiveMQ
    ActiveMQ 是Apache出品,最流行的,能力强劲的开源消息总线。ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的 JMS Provider实现。
  • RabbitMQ
    AMQP协议的领导实现,支持多种场景。淘宝的MySQL集群内部有使用它进行通讯,OpenStack开源云平台的通信组件,最先在金融行业得到运用。
  • ZeroMQ
    史上最快的消息队列系统
  • Kafka
    pache下的一个子项目 。特点:高吞吐,在一台普通的服务器上既可以达到10W/s的吞吐速率;完全的分布式系统。适合处理海量数据。

二、JMS

2.1 什么是JMS

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

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

2.2 JMS的五种消息正文格式

  • TextMessage–一个字符串对象
  • MapMessage–一套名称-值对
  • ObjectMessage–一个序列化的 Java 对象
  • BytesMessage–一个字节的数据流
  • StreamMessage – Java 原始值的数据流

2.3 JMS消息的传递类型

  • 点对点传递PTP(Point-to-point)

点对点传递,也可以叫队列模式,或分食模式。

即一条消息只会被一个消费方得到

  • 发布/订阅模式pub/sub(Publish/subscribe)

发布/订阅模式,也叫主题模式。

即一个生产者产生消息并发送后,可以被多个消费者接受

三、ActiveMQ下载和安装

可以在apache官网下https://activemq.apache.org/components/classic/download/下载各个版本的压缩包。

我下载的是windows下的zip压缩包,解压后去bin目录对应的系统位数目录下点击activemq.bat即可在windows环境下启动ActiveMQ

启动后访问http://127.0.0.1:8161/即可看到如下界面

在这里插入图片描述
点击Manage ActiveMQ broker进入管理界面

默认账号密码:admin

在这里插入图片描述
在此处可以观察队列模式和主题模式数据等信息,因现在无消息,所以没有数据显示

队列模式

在这里插入图片描述
主题模式

在这里插入图片描述

四、JMS模式(队列模式DEMO)

4.1 队列模式

生成的一条消息只能被一个消费者消费

4.2 依赖引入

创建maven项目,引入以下依赖

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

4.3 生产者创建

package com.cf.Producer;

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

import org.apache.activemq.ActiveMQConnectionFactory;

public class QueueProducer {

	public static void main(String[] args) throws Exception {
		//1.创建列表工厂  -- 默认端口61616
		ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://127.0.0.1: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.创建消息
		TextMessage textMessage = session.createTextMessage("JMS队列模式test");
		
		//8.发送消息
		producer.send(textMessage);
		
		//9.关闭资源
		producer.close();
		session.close();
		connection.close();
	}
	
}

4.4 消费者创建

package com.cf.consumer;

import javax.jms.Connection;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.apache.activemq.ActiveMQConnectionFactory;

public class QueueConsumer {

	public static void main(String[] args) throws Exception {
		//1.创建连接工厂 
		ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://127.0.0.1:61616");
		
		//2. 获取连接
		Connection connection = connectionFactory.createConnection();
		
		//3.启动连接
		connection.start();
		
		//4.获取session
		Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
		
		//5.创建队列对象
		Queue queue = session.createQueue("test-queue");
		
		//6.创建消息消费
		MessageConsumer consumer = session.createConsumer(queue);
		
		//7.监听消息
		consumer.setMessageListener(new MessageListener() {
			
			public void onMessage(Message message) {
				TextMessage textMessage = (TextMessage) message;
				try {
					System.out.println("接收到消息:" + textMessage.getText());
				} catch (JMSException e) {
					e.printStackTrace();
				}
			}
		});
		
		//8.等待键盘输入--保持监听状态
		System.in.read();	
		//9.关闭资源
		consumer.close();
		session.close();
		connection.close();

	}
}

4.5 运行结果

先启动生产者,在启动消费者。

控制台输出如下:

在这里插入图片描述
在ActiveMQ的管理界面中可以观察到生产者和消费者情况。
在这里插入图片描述
4.6 队列特征效果

清空控制台输出,运行两个消费者,此时两个消费者都进入等待状态。在运行一个生产者。

观察控制台输出。

可以看到只有一个消费者接受到了数据

收到信息的消费者
在这里插入图片描述
未收到信息的消费者
在这里插入图片描述

ActiveMQ管理界面,两个消费者,一条数据入队出队(图示两条数据记录一条为上例的记录,本例只产生了一条数据纪录,也可以重启ActiveMQ重置记录数)。
在这里插入图片描述

五、JMS模式(主题模式DEMO)

5.1 创建生产者

package com.cf.Producer;

import javax.jms.Connection;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;

import org.apache.activemq.ActiveMQConnectionFactory;

public class TopicProducer {

	public static void main(String[] args) throws Exception {
		//1.创建列表工厂  -- 默认端口61616
		ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://127.0.0.1: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.创建消息
		TextMessage textMessage = session.createTextMessage("JMS主题模式test");
		
		//8.发送消息
		producer.send(textMessage);
		
		//9.关闭资源
		producer.close();
		session.close();
		connection.close();
	}
	
}

5.2 创建消费者

package com.cf.consumer;

import javax.jms.Connection;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;

import org.apache.activemq.ActiveMQConnectionFactory;

public class TopicConsumer {
	public static void main(String[] args) throws Exception {
		// 1.创建连接工厂
		ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://127.0.0.1:61616");

		// 2. 获取连接
		Connection connection = connectionFactory.createConnection();

		// 3.启动连接
		connection.start();

		// 4.获取session
		Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

		// 5.创建队列对象
		Topic topic = session.createTopic("test-topic");

		// 6.创建消息消费
		MessageConsumer consumer = session.createConsumer(topic);

		// 7.监听消息
		consumer.setMessageListener(new MessageListener() {

			public void onMessage(Message message) {
				TextMessage textMessage = (TextMessage) message;
				try {
					System.out.println("接收到消息:" + textMessage.getText());
				} catch (JMSException e) {
					e.printStackTrace();
				}
			}
		});

		// 8.等待键盘输入--保持监听状态
		System.in.read();
		// 9.关闭资源
		consumer.close();
		session.close();
		connection.close();

	}
}

5.3 运行效果

运行两个消费者,一个生产者

控制台输出如下:

第一个消费者
在这里插入图片描述
第二个消费者

在这里插入图片描述
ActiveMQ的管理界面
在这里插入图片描述
对于主题模式, 消费者要先启动。 如果在生产者生产完成之后,再启动,是看不到消息的。

六、Spring模式(队列模式)

以上JSM的原始步骤较为繁琐。在Spring模式下整合JMS则会方便点,因为Spring对JMS原始API进行了封装

6.1 导入依赖

<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.cf</groupId>
	<artifactId>JMSDemo</artifactId>
	<version>0.0.1-SNAPSHOT</version>

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

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jms</artifactId>
			<version>4.2.4.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>4.2.4.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.9</version>
		</dependency>
	</dependencies>

</project>

6.2 配置文件

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">
		
		
	<context:component-scan base-package="com.cf.spring.producer"></context:component-scan>     
	
	   
    <!-- 真正可以产生Connection的ConnectionFactory,由对应的 JMS服务厂商提供-->  
	<bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">  
	    <property name="brokerURL" value="tcp://127.0.0.1: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>

applicationContext-jms-consumer.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">
	
    <!-- 真正可以产生Connection的ConnectionFactory,由对应的 JMS服务厂商提供-->  
	<bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">  
	    <property name="brokerURL" value="tcp://127.0.0.1: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="myMessageListener" class="com.cf.sprinig.consumer.MyMessageListener"></bean>
	<!-- 消息监听容器 -->
	<bean class="org.springframework.jms.listener.DefaultMessageListenerContainer">
		<property name="connectionFactory" ref="connectionFactory" />
		<property name="destination" ref="queueTextDestination" />
		<property name="messageListener" ref="myMessageListener" />
	</bean>
	
</beans>

6.3 Producer&Consumer class

QueueProducer.java

package com.cf.spring.producer;

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.stereotype.Component;

@Component
public class QueueProducer {

	@Autowired
	private JmsTemplate jmsTemplate;

	@Autowired
	private Destination queueTextDestination;

	/**
	 * 整合Spring方式发送text
	 * 
	 * @param text
	 */
	public void sentTextMessage(final String text) {
		jmsTemplate.send(queueTextDestination, new MessageCreator() {

			public Message createMessage(Session session) throws JMSException {

				return session.createTextMessage(text);
			}
		});

	}
}

MyMessageListener.java

package com.cf.sprinig.consumer;

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

/**
 * 
 * @author Administrator
 *接收消息
 */
public class MyMessageListener implements MessageListener{

	public void onMessage(Message message) {
		
		TextMessage textMessage = (TextMessage) message;
		
		try {
			System.out.println("接收到的消息" + textMessage.getText());
		} catch (JMSException e) {
			e.printStackTrace();
		}
	}

}

6.4 测试类

TestQueueConsumerDemo.java

package com.cf.test;

import java.io.IOException;

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

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext-jms-consumer.xml")
public class TestQueueConsumerDemo {
	
	@Test
	public void testQueue() {
		
		try {
			System.in.read(); //程序等待执行监听
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
}

TestQueueDemo.java

package com.cf.test;

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;

import com.cf.spring.producer.QueueProducer;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext-jms-producer.xml")
public class TestQueueDemo {

	@Autowired
	private QueueProducer queueProdcuer;
	
	@Test
	public void testSend()	{
		queueProdcuer.sentTextMessage("Spring JMS 队列主题测试");
	}
}

6.5 结果如下

先启动生产者:
在这里插入图片描述
在启动消费者
在这里插入图片描述
在这里插入图片描述

七、Spring模式(主题模式)

跟队列模式基本一致,把配置文件中队列有关改为主题模式即可,例子就先不放了,有空补一下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值