activeMQ

一.JMS

1.什么是JMS

JMS即Java消息服务(Java Message Service)应用程序接口,是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。Java消息服务是一个与具体平台无关的API,绝大多数MOM提供商都对JMS提供支持。

2.为什么要学JMS

在JAVA中,如果两个应用程序之间对各自都不了解,甚至这两个程序可能部署在不同的大洲上,那么它们之间如何发送消息呢?举个例子,一个应用程序A部署在印度,另一个应用程序部署在美国,然后每当A触发某件事后,B想从A获取一些更新信息。当然,也有可能不止一个B对A的更新信息感兴趣,可能会有N个类似B的应用程序想从A中获取更新的信息。在这种情况下,JAVA提供了最佳的解决方案-JMS,完美解决了上面讨论的问题。
JMS与RMI不同,发送消息的时候,接收者不需要在线。服务器发送了消息,然后就不管了;等到客户端上线的时候,能保证接收到服务器发送的消息。这是一个很强大的解决方案,能处理当今世界很多普遍问题。

3.JMS有什么优势

异步:JMS天生就是异步的,客户端获取消息的时候,不需要主动发送请求,消息会自动发送给可用的客户端。

可靠:JMS保证消息只会递送一次。大家都遇到过重复创建消息问题,而JMS能帮你避免该问题,只是避免而不是杜绝,所以在一些糟糕的环境下还是有可能会出现重复。

4.JMS数据交互的两种方式

(1)点对点消息模型

1、每个消息只有一个接受者(自己测试了一下,可以有多个接受者,但是当有多个接收者时,每个接收者只能获取随机的几条信息)
2、消息发送者和消息接受者并没有时间依赖性。
3、当消息发送者发送消息的时候,无论接收者程序在不在运行,都能获取到消息;
4、当接收者收到消息的时候,会发送确认收到通知(acknowledgement)。

点对点消息模型图
在这里插入图片描述
(2)发布/订阅消息模型

1、一个消息可以传递给多个订阅者
2、发布者和订阅者有时间依赖性,只有当客户端创建订阅后才能接受消息,且订阅者需一直保持活动状态以接收消息。
3、为了缓和这样严格的时间相关性,JMS允许订阅者创建一个可持久化的订阅。这样,即使订阅者没有被激活(运行),它也能接收到发布者的消息。

发布/订阅消息模型图:
在这里插入图片描述

5.ActiveMQ的消息形式

JMS定义了五种不同的消息正文格式,以及调用的消息类型,允许你发送并接收以一些不同形式的数据,提供现有消息格式的一些级别的兼容性。
  · StreamMessage – Java原始值的数据流
  · MapMessage–一套名称-值对
  · TextMessage–一个字符串对象
  · ObjectMessage–一个序列化的 Java对象
  · BytesMessage–一个字节的数据流

二.ActiveMQ

1.什么是ActiveMQ

ActiveMQ 是Apache出品,最流行的,能力强劲的开源消息总线。ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的 JMS Provider实现,尽管JMS规范出台已经是很久的事情了,但是JMS在当今的J2EE应用中间仍然扮演着特殊的地位。

2.启动

启动:进入你解压后的目录下的bin目录,运行
./activemq start

访问地址:
ActiveMQ 服务启动后台地址:http://127.0.0.1:8161/admin/ 用户名/密码 admin/admin

消息模式

(1)ActiveMQ的点对点使用
消息生产者 发送消息 到队列中 消费者 去 队列中拉取自己要的消息

(2)demo
首先启动ActiveMQ

然后编写Producter代码:JMSProducer.java

package com.miracle.one2one;

import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;

@SuppressWarnings("all")
public class JMSProducer {
    private static final String USERNAME= ActiveMQConnection.DEFAULT_USER; // 默认的连接用户名
    private static final String PASSWORD= ActiveMQConnection.DEFAULT_PASSWORD; // 默认的连接密码
    private static final String BROKEURL= ActiveMQConnection.DEFAULT_BROKER_URL; // 默认的连接地址

    public static void main(String[] args) {
        // 连接工厂
        ConnectionFactory connectionFactory = null;
        // 连接
        Connection connection = null;
        // 会话
        Session session = null;
        // 消息目的地
        Destination destination = null;
        // 消息生产者
        MessageProducer messageProducer = null;
        try {
            System.out.println(USERNAME);
            System.out.println(PASSWORD);
            System.out.println(BROKEURL);
            // 1.连接MQ
            connectionFactory = new ActiveMQConnectionFactory(USERNAME, PASSWORD, BROKEURL);
            connection = connectionFactory.createConnection();
            connection.start();

            /*
                Session.AUTO_ACKNOWLEDGE。当客户成功的从receive 方法返回的时候,或者从MessageListener.onMessage方法成功返回的时候,会话自动确认客户收到的消息。
                Session.CLIENT_ACKNOWLEDGE。 客户通过消息的 acknowledge 方法确认消息。需要注意的是,在这种模式中,确认是在会话层上进行:确认一个被消费的消息将自动确认所有已被会话消费的消息。例如,如果一个消息消费者消费了 10 个消息,然后确认第 5 个消息,那么所有 10 个消息都被确认。
                Session.DUPS_ACKNOWLEDGE。 该选择只是会话迟钝的确认消息的提交。如果 JMS provider 失败,那么可能会导致一些重复的消息。如果是重复的消息,那么 JMS provider 必须把消息头的 JMSRedelivered 字段设置
                为 true。
             */

            session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
            destination = session.createQueue("短信发送");
            messageProducer = session.createProducer(destination);

            // 2.发送消息
            for (int i = 0; i < 10; i++) {
                // 模拟消息
                String txt = "1760829525" + i;
                // 构造消息对象
                TextMessage textMessage = session.createTextMessage(txt);
                // 发送
                messageProducer.send(textMessage);
            }
            // 提交session
            session.commit();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            // 3.断开
            try {
                messageProducer.close();
                session.close();
                connection.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

然后执行,登录ActiveMQ管理页面,可以看到Producter向队列发送的消息
在这里插入图片描述
然后编写Consumer代码:JMSConsumer.java

package com.miracle.one2one;

import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;

@SuppressWarnings("all")
public class JMSConsumer {
    private static final String USERNAME= ActiveMQConnection.DEFAULT_USER; // 默认的连接用户名
    private static final String PASSWORD= ActiveMQConnection.DEFAULT_PASSWORD; // 默认的连接密码
    private static final String BROKEURL= ActiveMQConnection.DEFAULT_BROKER_URL; // 默认的连接地址

    public static void main(String[] args) {
        // 连接工厂
        ConnectionFactory connectionFactory = null;
        // 连接
        Connection connection = null;
        // 会话
        Session session = null;
        // 消息目的地
        Destination destination = null;
        // 消息消费者
        MessageConsumer messageConsumer = null;
        try {
            System.out.println(USERNAME);
            System.out.println(PASSWORD);
            System.out.println(BROKEURL);
            // 1.连接MQ
            connectionFactory = new ActiveMQConnectionFactory(USERNAME, PASSWORD, BROKEURL);
            connection = connectionFactory.createConnection();
            connection.start();

            /*
                Session.AUTO_ACKNOWLEDGE。当客户成功的从receive 方法返回的时候,或者从MessageListener.onMessage方法成功返回的时候,会话自动确认客户收到的消息。
                Session.CLIENT_ACKNOWLEDGE。 客户通过消息的 acknowledge 方法确认消息。需要注意的是,在这种模式中,确认是在会话层上进行:确认一个被消费的消息将自动确认所有已被会话消费的消息。例如,如果一个消息消费者消费了 10 个消息,然后确认第 5 个消息,那么所有 10 个消息都被确认。
                Session.DUPS_ACKNOWLEDGE。 该选择只是会话迟钝的确认消息的提交。如果 JMS provider 失败,那么可能会导致一些重复的消息。如果是重复的消息,那么 JMS provider 必须把消息头的 JMSRedelivered 字段设置
                为 true。
             */

            session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
            destination = session.createQueue("短信发送");
            messageConsumer = session.createConsumer(destination);

            // 2.接收消息,这里只取5条消息,当第二次调用此方法可以取剩余5条消息

            // (1) 主动从队列中取数据
//            for (int i = 0; i < 5; i++) {
//                // 调用一次recevice取一条消息
//                TextMessage textMessage = (TextMessage)messageConsumer.receive();
//                System.out.println(textMessage.getText());
//            }
//          提交session
//          session.commit();

            // (2) 编写监听器,监听队列数据,当队列有数据时,执行监听器的onMessage方法
            messageConsumer.setMessageListener(new MyMessageListener());
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

监听类:MyMessageListener.java

package com.miracle.one2one;

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

public class MyMessageListener implements MessageListener {

    @Override
    public void onMessage(Message message) {
        TextMessage textMessage = (TextMessage)message;
        if (textMessage != null){
            try {
                System.out.println(textMessage.getText());
            } catch (JMSException e) {
                e.printStackTrace();
            }
        }
    }
}

(2)ActiveMQ的发布和订阅

消息生产者 发送消息 到队列中 队列会把消息推送到 消费者(需要订阅消息,并监听推送)那里,消费者可能是一个或者多个

编写 两个 监听 :MyMessageListener1.java,MyMessageListener2.java

package com.miracle.subscriber;

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

@SuppressWarnings("all")
public class MyMessageListener1 implements MessageListener {

    @Override
    public void onMessage(Message message) {
        TextMessage textMessage = (TextMessage)message;
        if (textMessage != null){
            try {
                System.out.println("Consumer1从MQ获取的消息" + textMessage.getText());
            } catch (JMSException e) {
                e.printStackTrace();
            }
        }
    }
}
package com.miracle.subscriber;

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

@SuppressWarnings("all")
public class MyMessageListener2 implements MessageListener {

    @Override
    public void onMessage(Message message) {
        TextMessage textMessage = (TextMessage)message;
        if (textMessage != null){
            try {
                System.out.println("Consumer2从MQ获取的消息" + textMessage.getText());
            } catch (JMSException e) {
                e.printStackTrace();
            }
        }
    }
}

编写 两个 消费者 订阅消息 :JMSConsumer1.java,JMSConsumer2.java

package com.miracle.subscriber;

import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;

@SuppressWarnings("all")
public class JMSConsumer1 {
    private static final String USERNAME= ActiveMQConnection.DEFAULT_USER; // 默认的连接用户名
    private static final String PASSWORD= ActiveMQConnection.DEFAULT_PASSWORD; // 默认的连接密码
    private static final String BROKEURL= ActiveMQConnection.DEFAULT_BROKER_URL; // 默认的连接地址

    public static void main(String[] args) {
        // 连接工厂
        ConnectionFactory connectionFactory = null;
        // 连接
        Connection connection = null;
        // 会话
        Session session = null;
        // 消息目的地
        Destination destination = null;
        // 消息消费者
        MessageConsumer messageConsumer = null;
        try {
            System.out.println(USERNAME);
            System.out.println(PASSWORD);
            System.out.println(BROKEURL);
            // 1.连接MQ
            connectionFactory = new ActiveMQConnectionFactory(USERNAME, PASSWORD, BROKEURL);
            connection = connectionFactory.createConnection();
            connection.start();

            /*
                Session.AUTO_ACKNOWLEDGE。当客户成功的从receive 方法返回的时候,或者从MessageListener.onMessage方法成功返回的时候,会话自动确认客户收到的消息。
                Session.CLIENT_ACKNOWLEDGE。 客户通过消息的 acknowledge 方法确认消息。需要注意的是,在这种模式中,确认是在会话层上进行:确认一个被消费的消息将自动确认所有已被会话消费的消息。例如,如果一个消息消费者消费了 10 个消息,然后确认第 5 个消息,那么所有 10 个消息都被确认。
                Session.DUPS_ACKNOWLEDGE。 该选择只是会话迟钝的确认消息的提交。如果 JMS provider 失败,那么可能会导致一些重复的消息。如果是重复的消息,那么 JMS provider 必须把消息头的 JMSRedelivered 字段设置
                为 true。
             */

            session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
            destination = session.createTopic("短信发送T");
            messageConsumer = session.createConsumer(destination);

            // 编写监听器,监听队列数据,当队列有数据时,执行监听器的onMessage方法
            messageConsumer.setMessageListener(new MyMessageListener1());
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
package com.miracle.subscriber;

import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;

@SuppressWarnings("all")
public class JMSConsumer2 {
    private static final String USERNAME= ActiveMQConnection.DEFAULT_USER; // 默认的连接用户名
    private static final String PASSWORD= ActiveMQConnection.DEFAULT_PASSWORD; // 默认的连接密码
    private static final String BROKEURL= ActiveMQConnection.DEFAULT_BROKER_URL; // 默认的连接地址

    public static void main(String[] args) {
        // 连接工厂
        ConnectionFactory connectionFactory = null;
        // 连接
        Connection connection = null;
        // 会话
        Session session = null;
        // 消息目的地
        Destination destination = null;
        // 消息消费者
        MessageConsumer messageConsumer = null;
        try {
            System.out.println(USERNAME);
            System.out.println(PASSWORD);
            System.out.println(BROKEURL);
            // 1.连接MQ
            connectionFactory = new ActiveMQConnectionFactory(USERNAME, PASSWORD, BROKEURL);
            connection = connectionFactory.createConnection();
            connection.start();

            /*
                Session.AUTO_ACKNOWLEDGE。当客户成功的从receive 方法返回的时候,或者从MessageListener.onMessage方法成功返回的时候,会话自动确认客户收到的消息。
                Session.CLIENT_ACKNOWLEDGE。 客户通过消息的 acknowledge 方法确认消息。需要注意的是,在这种模式中,确认是在会话层上进行:确认一个被消费的消息将自动确认所有已被会话消费的消息。例如,如果一个消息消费者消费了 10 个消息,然后确认第 5 个消息,那么所有 10 个消息都被确认。
                Session.DUPS_ACKNOWLEDGE。 该选择只是会话迟钝的确认消息的提交。如果 JMS provider 失败,那么可能会导致一些重复的消息。如果是重复的消息,那么 JMS provider 必须把消息头的 JMSRedelivered 字段设置
                为 true。
             */

            session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
            destination = session.createTopic("短信发送T");
            messageConsumer = session.createConsumer(destination);

            // 编写监听器,监听队列数据,当队列有数据时,执行监听器的onMessage方法
            messageConsumer.setMessageListener(new MyMessageListener2());
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

编写 一个 订阅内容发布者:JMSProducer.java

package com.miracle.subscriber;

import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;

import javax.jms.*;

@SuppressWarnings("all")
public class JMSProducer {
    private static final String USERNAME= ActiveMQConnection.DEFAULT_USER; // 默认的连接用户名
    private static final String PASSWORD= ActiveMQConnection.DEFAULT_PASSWORD; // 默认的连接密码
    private static final String BROKEURL= ActiveMQConnection.DEFAULT_BROKER_URL; // 默认的连接地址

    public static void main(String[] args) {
        // 连接工厂
        ConnectionFactory connectionFactory = null;
        // 连接
        Connection connection = null;
        // 会话
        Session session = null;
        // 消息目的地
        Destination destination = null;
        // 消息生产者
        MessageProducer messageProducer = null;
        try {
            System.out.println(USERNAME);
            System.out.println(PASSWORD);
            System.out.println(BROKEURL);
            // 1.连接MQ
            connectionFactory = new ActiveMQConnectionFactory(USERNAME, PASSWORD, BROKEURL);
            connection = connectionFactory.createConnection();
            connection.start();

            /*
                Session.AUTO_ACKNOWLEDGE。当客户成功的从receive 方法返回的时候,或者从MessageListener.onMessage方法成功返回的时候,会话自动确认客户收到的消息。
                Session.CLIENT_ACKNOWLEDGE。 客户通过消息的 acknowledge 方法确认消息。需要注意的是,在这种模式中,确认是在会话层上进行:确认一个被消费的消息将自动确认所有已被会话消费的消息。例如,如果一个消息消费者消费了 10 个消息,然后确认第 5 个消息,那么所有 10 个消息都被确认。
                Session.DUPS_ACKNOWLEDGE。 该选择只是会话迟钝的确认消息的提交。如果 JMS provider 失败,那么可能会导致一些重复的消息。如果是重复的消息,那么 JMS provider 必须把消息头的 JMSRedelivered 字段设置
                为 true。
             */

            session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
            destination = session.createTopic("短信发送T");
            messageProducer = session.createProducer(destination);

            // 2.发送消息
            for (int i = 0; i < 10; i++) {
                // 模拟消息
                String txt = "1760829525" + i;
                // 构造消息对象
                TextMessage textMessage = session.createTextMessage(txt);
                // 发送
                messageProducer.send(textMessage);
            }
            // 提交session
            session.commit();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            // 3.断开
            try {
                messageProducer.close();
                session.close();
                connection.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

三.spring整合ActiveMQ

1.jar包依赖

<dependency>
    <groupId>org.apache.activemq</groupId>
    <artifactId>activemq-all</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-jms</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-context-support</artifactId>
</dependency>

2.配置Activemq整合spring。配置ConnectionFactory

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
	http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
	http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd">


	<!-- 真正可以产生Connection的ConnectionFactory,由对应的 JMS服务厂商提供 -->
	<bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
		<property name="brokerURL" value="tcp://192.168.25.168: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="queueDestination" class="org.apache.activemq.command.ActiveMQQueue">
		<constructor-arg name="name" value="queue"></constructor-arg>
	</bean>
	<!--这个是主题目的地,一对多的 -->
	<bean id="topicDestination" class="org.apache.activemq.command.ActiveMQTopic">
		<constructor-arg name="name" value="topic"></constructor-arg>
	</bean>
</beans>

3.使用JMSTemplate发送消息

@Test
public void testQueueProducer() throws Exception {
	// 第一步:初始化一个spring容器
	ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring/applicationContext-activemq.xml");
	// 第二步:从容器中获得JMSTemplate对象。
	JmsTemplate jmsTemplate = applicationContext.getBean(JmsTemplate.class);
	// 第三步:从容器中获得一个Destination对象
	Destination destination = (Destination) applicationContext.getBean("queueDestination");
	// 第四步:使用JMSTemplate对象发送消息,需要知道Destination
	jmsTemplate.send(queue, new MessageCreator() {
		
		@Override
		public Message createMessage(Session session) throws JMSException {
			TextMessage textMessage = session.createTextMessage("spring activemq test");
			return textMessage;
		}
	});
}

4.使用JMSTemplate接收消息

  • 创建一个MessageListener的实现类
public class MyMessageListener implements MessageListener {

	@Override
	public void onMessage(Message message) {
		
		try {
			TextMessage textMessage = (TextMessage) message;
			//取消息内容
			String text = textMessage.getText();
			System.out.println(text);
		} catch (JMSException e) {
			e.printStackTrace();
		}
	}
}
  • 在spring配置中,添加 配置 监听器 和 消息监听容器
<!-- 接收消息 -->
<!-- 配置监听器 -->
<bean id="myMessageListener" class="com.taotao.search.listener.MyMessageListener" />
<!-- 消息监听容器 -->
<bean class="org.springframework.jms.listener.DefaultMessageListenerContainer">
	<property name="connectionFactory" ref="connectionFactory" />
	<property name="destination" ref="queueDestination" />
	<property name="messageListener" ref="myMessageListener" />
</bean>
  • 使用代码
@Test
public void testQueueConsumer() throws Exception {
	//初始化spring容器
	ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring/applicationContext-activemq.xml");
	//等待
	System.in.read();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值