ActiveMQ的简介,安装,使用。

简介

1.what(什么是ActiveMQ)

    ActiveMQ 是Apache出品的最流行的,能力强劲的开源消息总线。ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的 JMS Provider实现,尽管JMS规范出台已经是很久的事情了,但是JMS在当今的J2EE应用中间仍然扮演着特殊的地位。
解释:
     MQ: message queue ,消息队列,也叫消息中间件
     JMS:即Java消息服务(Java Message Service)应用程序接口,是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。
     ActiveMQ:即是对JMS规范的实现,简单说就是两个程序或者分布式系统中系统之间的异步通信实现

即:JMS是系统之间通信的规范,ActiveMQ是JMS的一种实现。

除了ActiveMQ之外其他的实现还有:RabbitMQ、kafka等都属于MQ,是MQ的产品。

2.why(为什么要使用它?)

    为什么要使用它?,可以理解为它可以帮助我们完成那些事情,即他的作用是什么?

    在分布式的SOA架构系统中,我们进行完整的服务操作难免需要依赖其他的服务,例如:我针对某一商品进行了修改,可能要影响我商品的显示(缓存),查询(索引)等。而这些服务的逻辑可能别的系统中。
    可解决的思路如下:
        1.在当前服务下,续写别的服务的代码 (很明显代码冗余)
        2.系统服务之间的通信(WebService,Duboo 等,这是很不错的方案)
        3.通过消息队列,修改商品时发送消息,在别的系统中监听消息,然后针对这一消息做出响应。

可以看出:使用消息队列解决系统之间通信的优点是:降低了系统之间代码的耦合度,也降低的服务的管理难度,即在当前服务中不存在所依赖服务的代码,而是通过发送消息的方式,通知相应的系统做出相应的响应。

3.where(在那里使用?)

    通过上述的分析,我们已经很容易可以看出,消息队列是用于系统之间进行通信的一种方式。

栗子:
    xx商城的后台管理系统需要对A商品进行修改,而A商品的销售情况非常好,所以在前端商品页面中存在redis缓存。现在要对A的价格进行调动,此时如果利用消息队列来实现, 则在A修改的时候,发送一条消息出去,此时前台系统监听接受到该消息后重置该商品的缓存,以保证数据的准确性。

安装

1.环境准备

  1. Linux系统
  2. JDK
  3. ActiveMQ安装包(Apahc官方下载安装即可)

2.Linux下安装JDK

1.登录,切换到root用户
2.在usr目录下新建Java文件夹

   mkdir /usr/java

3.拷贝jdk的文件夹到该目录,然后解压

  cp  jdk的目录  /usr/java
  tar -zxvf jdk目录

4.编辑配置文件,配置环境变量

vim /etc/profile


添加如下内容:JAVA_HOME根据实际目录来
JAVA_HOME=/usr/java/jdk1.8.0_60
CLASSPATH=$JAVA_HOME/lib/
PATH=$PATH:$JAVA_HOME/bin
export PATH JAVA_HOME CLASSPATH

5.重启机器或重置profile文件

方式1:重新加载profile文件  source /etc/profile  (推荐)
方式2:重启机器   sudo shutdown -r now

6.检测安装是否成功

java -version

如出现jdk的版本信息,则安装成功。

3.安装ActiveMQ

1.官网下载ActiveMQ后,上传到Linux系统中
2.解压
3.进入bin文件启动ActiveMQ即可(内置jetty服务器)

  启动: ./activemq start
  关闭: ./activemq stop
  查看状态: ./activemq status

在这里插入图片描述
4.在浏览器输入 http://ip:8161/admin
    回车后输入账号和密码都为admin即可。
在这里插入图片描述

使用

1.理论知识

对于消息的传递有两种类型:
    一种是点对点的,即一个生产者和一个消费者一一对应;
在这里插入图片描述
    另一种是发布/订阅模式,即一个生产者产生消息并进行发送后,可以由多个消费者进行接收。
在这里插入图片描述
JMS定义了五种不同的消息正文格式,以及调用的消息类型,允许你发送并接收以一些不同形式的数据,提供现有消息格式的一些级别的兼容性。
  · StreamMessage – Java原始值的数据流
  · MapMessage–一套名称-值对
  · TextMessage–一个字符串对象
  · ObjectMessage–一个序列化的 Java对象
  · BytesMessage–一个字节的数据流

2.常用的API

导入依赖:

		<dependency>
			<groupId>org.apache.activemq</groupId>
			<artifactId>activemq-all</artifactId>
			<version>5.15.8</version>
		</dependency>

1>点对点(一对一)-Queue

生产者:

@Test
	public void testMQProducerQueue() throws JMSException {
		// 1. 创建工厂对象-->需要指定ip和端口
		ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.25.133:61616");
		// 2.通过连接工厂构建 构建一个真实连接对象
		Connection connection = connectionFactory.createConnection();
		// 3.开启连接
		connection.start();
		// 4.通过连接对象,构建一个session回话对象
		// 参数1: 是否开启事务 参数2:消息的应答模式只有1为false才有效,手动?自动
		Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
		// 5.通过会话对象,构建一个Destination对象(queue 、 topic) ,指明消息发送的模式
		// Destination 目的的 queue队列(一对一)、topic主题(一对多),参数:就是本次消息的名字
		Queue queue = session.createQueue("test-queue");
		// 6.通过回话创建一个消息发送者 ,并且指明发送消息的传递类型
		MessageProducer producer = session.createProducer(queue);
		// 7.构建消息 Message,此处构建一个TextMessage;
		TextMessage textMessage = session.createTextMessage("this is queue first message: Hello World");
		// 8.发送消息
		producer.send(textMessage);
		// 9. 关闭资源
		producer.close();
		session.close();
		connection.close();
	}

消费者

    @Test
	public void testMQConsumerQueue() throws JMSException, InterruptedException {

		// 1. 创建连接工厂
		ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.25.133:61616");
		// 2.构建真实的连接
		Connection connection = connectionFactory.createConnection();
		// 3.开启连接
		connection.start();
		// 4.通过连接 构建session
		Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
		// 5.通过session 构建接受消息的模式以及名字
		Queue queue = session.createQueue("test-queue");
		// 6.通过session 构建一个消息接受者,指明要接受的队列模式
		MessageConsumer consumer = session.createConsumer(queue);
		// 7. 监听该队列,接受消息
		consumer.setMessageListener(message -> {
			if (message != null && message instanceof TextMessage) {
				TextMessage textMessage = (TextMessage) message;
				try {
					System.out.println(textMessage.getText());
				} catch (JMSException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		});
       // 此处的休眠,目的是为了防止主线程先结束,导致开启的监听消息的线程还未接受的消息就挂了。
		Thread.sleep(2000000);
		// 8 .关闭资源
		consumer.close();
		session.close();
		connection.close();
	}

测试:
发送之前:
在这里插入图片描述
发送一条消息:运行testMQProducerQueue()
在这里插入图片描述
接受消息后:
在这里插入图片描述 待处理消息为0,由于我们睡眠的时间比较久,所以目前消费者为1(当前sleep结束后则为0),消费的消息为1.

栗子1:我们连续发送两条消息,然后开启一个接收方:
在这里插入图片描述可以看出只要消费者线程不关闭,他就会一直获取消息。
如果有两个消费者会怎样呢?

栗子2:一条消息,两个消费者:
    大家可以自己手动测试看看,可以发现,消息的传递是轮询的,即A一次,B一次,
先开启的消费者会优先得到第一次消息。

通过上述的案例我们可以看出Queue模式的特点:queue消息
默认是存在于MQ的服务器中的,发送消息之后,随时取。但是一定是一个消费者取完就没了。

2>发布/订阅(一对多)-Topic

这里我就不贴代码了,只需要把上述一对一中Queue改成Topic即可。
在这里插入图片描述
栗子1:先发送消息,在接受消息。
无法接受到消息,查看后,发现确实存在一套消息,但是已处理消息为0。
在这里插入图片描述原因很简单,topic的消息不会存在于MQ中,所以必须先开启消费者,在发送消息。
在这里插入图片描述
从左->右 : 一个消费者(线程未关闭),总共两条消息,一条已处理消息。

栗子2:发送一条消息,多个(两个)接受者。
在这里插入图片描述 可以看出发送了一条消息,但是接受了两条消息。

3.Spring整合ActiveMQ

导入依赖:
spring+activemq(这里我们直接导入webmvc的依赖)

	   <dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>4.3.16.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.apache.activemq</groupId>
			<artifactId>activemq-all</artifactId>
			<version>5.15.8</version>
		</dependency>

这里我们没有引入spring和activemq的整合包,但是后边的程序却没有出错,所以大家依据自己的情况尝试。
在这里插入图片描述

1>生产者配置

applicationContext配置文件

    <!--配置ActiveMQ的连接工厂-->
	<bean id="targetConnection"
		class="org.apache.activemq.ActiveMQConnectionFactory">
		<property name="brokerURL" value="tcp://192.168.25.133:61616"></property>
	</bean>
	<!-- 通用的connectionfacotry 指定真正使用的连接工厂 -->
	<bean id="connectionFactory"
		class="org.springframework.jms.connection.SingleConnectionFactory">
		<property name="targetConnectionFactory"
			ref="targetConnection"></property>
	</bean>
	<!-- 接收和发送消息时使用的类 -->
	<bean class="org.springframework.jms.core.JmsTemplate">
		<property name="connectionFactory" ref="connectionFactory"></property>
	</bean>
	<!-- 配置destination -->
	<!-- 队列目的地 -->
	<bean id="queueDestination"
		class="org.apache.activemq.command.ActiveMQQueue">
		<constructor-arg name="name" value="item-change-queue"></constructor-arg>
	</bean>
	<!-- 话题目的地 -->
	<bean id="topicDestination"
		class="org.apache.activemq.command.ActiveMQTopic">
		<constructor-arg name="name" value="item-change-topic"></constructor-arg>
	</bean> 

Java测试代码

	@Test
	public void send() throws Exception {
		// 1.初始化spring容器
		ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext-activemq.xml");
		// 2.获取到jmstemplate的对象
		JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);
		// 3.获取destination
		Destination destination = (Destination) context.getBean("queueDestination");
		// 4.发送消息
		jmsTemplate.send(destination, new MessageCreator() {

			public Message createMessage(Session session) throws JMSException {
				return session.createTextMessage("通过spring发送的消息123");
			}
		});
	}

2>消费者配置

applicationContext配置文件

    <!--配置ActiveMQ的连接工厂-->
	<bean id="targetConnection"
		class="org.apache.activemq.ActiveMQConnectionFactory">
		<property name="brokerURL" value="tcp://192.168.25.133:61616"></property>
	</bean>
	<!-- 通用的connectionfacotry 指定真正使用的连接工厂 -->
	<bean id="connectionFactory"
		class="org.springframework.jms.connection.SingleConnectionFactory">
		<property name="targetConnectionFactory"
			ref="targetConnection"></property>
	</bean>
	<!-- 配置destination -->
	<!-- 队列目的地 -->
	<bean id="queueDestination"
		class="org.apache.activemq.command.ActiveMQQueue">
		<constructor-arg name="name" value="item-change-queue"></constructor-arg>
	</bean>
	<!-- 话题目的地 -->
	<bean id="topicDestination"
		class="org.apache.activemq.command.ActiveMQTopic">
		<constructor-arg name="name" value="item-change-topic"></constructor-arg>
	</bean>
	<!-- 配置自定义监听器 -->
	<bean id="myMessageListener"
		class="activemq_consumer.MyMessageListener"></bean>
	<!-- 配置监听器容器 -->
	<bean
		class="org.springframework.jms.listener.DefaultMessageListenerContainer">
		<property name="connectionFactory" ref="connectionFactory"></property>
		<property name="destination" ref="queueDestination"></property>
		<property name="messageListener" ref="myMessageListener"></property>
	</bean>

自定义监听器

public class MyMessageListener implements MessageListener {

	public void onMessage(Message message) {
		if (message instanceof TextMessage) {
			TextMessage textMessage = (TextMessage) message;
			String text;
			try {
				text = textMessage.getText();
				System.out.println(text);
			} catch (JMSException e) {
				e.printStackTrace();
			}
		}
	}
}

测试代码:

@Test
	public void consumer() throws InterruptedException {
		ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext-activemq.xml");
		//sleep的目的是为了,防止因线程结束,而接受不到消息
		Thread.sleep(100000);
	}

3>测试

详细测试代码这里就不说了,大家仿照之前的进行测试就好。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值