java操作ActiveMQ整理

一、基础学习

首先导入pom依赖

    <!-- activemq -->
    <dependency>
        <groupId>org.apache.activemq</groupId>
        <artifactId>activemq-all</artifactId>
        <version>5.11.0</version>
    </dependency>
    <!--jmsTemplate -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jms</artifactId>
        <version>4.1.4.RELEASE</version>
    </dependency>

1.发送和接收队列(Queue)消息

发送

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.apache.activemq.ActiveMQConnectionFactory;

public class Sender {

	public static void main(String[] args) {
        // 连接工厂
        ConnectionFactory connectionFactory= new ActiveMQConnectionFactory(
               "admin",
                "admin",
                "tcp://localhost:61616");;
        //JMS 客户端到JMS Provider 的连接
        //发送消息的是生产者producer mq的服务器是提供者provider 接受消息的是消费者
        Connection connection = null;
        // Session: 一个发送或接收消息的线程
        //可以设置事务和确认方式
        Session session = null;
        // Destination :消息的目的地;消息发送给谁.
        //可以是一个topic 也可以是一个queue
        Destination destination;
        // MessageProducer:消息生产者
        MessageProducer producer;
        // 构造ConnectionFactory实例对象,此处采用ActiveMq的实现jar
        connectionFactory = new ActiveMQConnectionFactory(
               "admin",
                "admin",
                "tcp://localhost:61616");
        try {
            connection = connectionFactory.createConnection();
            // 启动
            connection.start();
            //createSession 第一个参数transacted 表示是否支持事务 
            //第二个参数 acknowledgeMode 有如下几种
            //1.AUTO_ACKNOWLEDGE 自动确认模式,不需客户端进行确认
            //2.CLIENT_ACKNOWLEDGE   客户端进行确认
            //客户端获得message之后需要进行message.acknowledge();
            //3.DUPS_OK_ACKNOWLEDGE  允许重复消息
            session = connection.createSession(Boolean.TRUE,
                    Session.AUTO_ACKNOWLEDGE);
            // 创建队列名为FirstQueue的目的地
            destination = session.createQueue("FirstQueue");
            // 创建将消息发送到该目的地的消息生产者
            producer = session.createProducer(destination);
            // 持久化模式 NON_PERSISTENT不持久化,PERSISTENT持久化
            producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
            TextMessage message = session
                    .createTextMessage("ActiveMq 发送的消息");
            // 发送消息到目的地方
            producer.send(message);
            //也可以这样
            //producer.send(
            //		message,//要发送的消息
            //		DeliveryMode.NON_PERSISTENT,//是否持久化
            //		1,//消息优先级 1-4位普通消息,5-9位加急消息,不严格按照优先级发送,但会保证加急消息优先发送 默认级别为4
            //		1000L//消息过期时间,默认永不过期,单位毫秒
            //		);
            System.out.println("发送消息***");
            session.commit();
        } catch (Exception e) {
        	try {
        		if(null != session){
    				session.rollback();
        		}
			} catch (JMSException e1) {
				e1.printStackTrace();
			}
            e.printStackTrace();
        } finally {
            try {
                if (null != connection)
                    connection.close();
            } catch (Throwable ignore) {
            }
        }
    
	}
}

接收

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.MessageConsumer;
import javax.jms.Session;
import javax.jms.TextMessage;

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

public class Receiver {
	public static void main(String[] args) {
        ConnectionFactory connectionFactory;
        Connection connection = null;
        Session session;
        Destination destination;
        MessageConsumer consumer;
        connectionFactory = new ActiveMQConnectionFactory(
                ActiveMQConnection.DEFAULT_USER,
                ActiveMQConnection.DEFAULT_PASSWORD,
                "tcp://localhost:61616");
        try {
            connection = connectionFactory.createConnection();
            connection.start();
            session = connection.createSession(Boolean.FALSE,
                    Session.AUTO_ACKNOWLEDGE);
            destination = session.createQueue("FirstQueue");
            consumer = session.createConsumer(destination);
            while (true) {
                //设置接收者接收消息的时间,
                TextMessage message = (TextMessage) consumer.receive(1000);
                if (null != message) {
                	//如果生产者设置消息确认模式为CLIENT_ACKNOWLEDGE 则需要客户端进行确认
                	/*
                	try {
                    	message.acknowledge();
					} catch (Exception e) {
						//确认消息过程中发生异常进行处理
					}
                	 */
                    System.out.println("收到消息:" + message.getText());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != connection){
                    connection.close();
                }
            } catch (Throwable ignore) {
            }
        }
    }
}

先启动接收的方法,然后启动发送的方法得到如下结果

这是同步获取消息,也可以这样设置监听来异步获取消息


            consumer.setMessageListener(new MessageListener() {
				
				public void onMessage(Message message) {
                  try {
					System.out.println("收到消息:" + ((TextMessage)message).getText());
					} catch (JMSException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			});
            while(true){
            	Thread.sleep(1000);
            }

2.发送和接收主题(Topic)消息

只要将destination改为

destination = session.createTopic("FirstTopic");

即可。

Topic和Queue都是属于Destination的一种,创建连接的时候也可以直接创建发送Queue消息或Topic消息的的连接工厂

	TopicConnectionFactory factory = new ActiveMQConnectionFactory(
			ActiveMQConnection.DEFAULT_USER,
			ActiveMQConnection.DEFAULT_PASSWORD, BROKER_URL);
	TopicConnection connection = factory.createTopicConnection();
	connection.start();
	TopicSession session = connection.createTopicSession(Boolean.TRUE,
			Session.AUTO_ACKNOWLEDGE);

将Topic改为Queue也是一样的

TopicSession可以创建发布者Publisher和订阅者Subscriber,其中Publisher属于Producer,Subscriber属于Consumer

3.使用JmsTemplate

以下以Queue为模板,Topic的话只要把Destination缓存Topic就可以了

发送消息

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

import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQQueue;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;

public class TemplateSender{
	public static void main(String[] args) {
		/*
		 * 这些可以写在spring配置文件中,使用时直接获取jmsTemplate这个bean就可以
		 */
		ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
	               "admin",
	                "admin",
	                "tcp://localhost:61616");
		JmsTemplate jmsTemplate = new JmsTemplate();
		jmsTemplate.setConnectionFactory(connectionFactory);
		jmsTemplate.setDefaultDestination(new ActiveMQQueue("queue1"));
		jmsTemplate.setReceiveTimeout(1000);
		//发送消息
		jmsTemplate.send(new MessageCreator() {
			
			public Message createMessage(Session session) throws JMSException {
				MapMessage mapMessage = session.createMapMessage();
				mapMessage.setString("aaa", "value1");
				mapMessage.setBoolean("bbb", true);
				return mapMessage;
			}
		});
		System.out.println("发送消息");
	}
}

同步接收消息

import java.util.Map;

import javax.jms.ConnectionFactory;

import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQQueue;
import org.springframework.jms.core.JmsTemplate;

public class TemplateReceiver {
	public static void main(String[] args) {
		ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
	               "admin",
	                "admin",
	                "tcp://localhost:61616");
		JmsTemplate jmsTemplate = new JmsTemplate();
		jmsTemplate.setConnectionFactory(connectionFactory);
		jmsTemplate.setDefaultDestination(new ActiveMQQueue("queue1"));
		jmsTemplate.setReceiveTimeout(1000);
		//同步接收消息
		while(true){
        	try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			Map<String, Object> message = (Map<String,Object>) jmsTemplate.receiveAndConvert();
			if(message != null){
				System.out.println(message.get("aaa"));
				System.out.println(message.get("bbb"));
			}
		}
	}
}

异步接收消息,要用到MessageListenerContainer

import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.MapMessage;
import javax.jms.Message;
import javax.jms.MessageListener;

import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQQueue;
import org.springframework.jms.listener.DefaultMessageListenerContainer;

public class ContainerReceiver {
	public static void main(String[] args) {

		ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
	               "admin",
	                "admin",
	                "tcp://localhost:61616");
		
		//异步接收消息
		DefaultMessageListenerContainer container = new DefaultMessageListenerContainer();
		container.setConnectionFactory(connectionFactory);
		container.setDestination(new ActiveMQQueue("queue1"));
		container.setMessageListener(new MessageListener() {
			
			public void onMessage(Message message) {
				if (message != null) {
					MapMessage map = (MapMessage) message;
					try {
						System.out.println(map.getString("aaa"));
						System.out.println(map.getBoolean("bbb"));
					} catch (JMSException e) {
						e.printStackTrace();
					}
				}
			}
		});
		container.afterPropertiesSet();
		container.start();
		while (true){
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

集成spring配置可以这样写

application.xml

    <!-- 配置连接工厂 -->
    <bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
        <property name="brokerURL" value="failover:(tcp://localhost:61616)" />
        <property name="userName" value="admin"/>
        <property name="password" value="admin"/>
    </bean>

    <!-- 目的地 -->
    <bean id="queueDestination" class="org.apache.activemq.command.ActiveMQQueue">
        <constructor-arg>
            <value>queue1</value>
        </constructor-arg>
    </bean>
    <!-- 监听器 -->
    <bean id="queueListener" class="com.jsyl.activeMQTest.mq.QueueListener">
    </bean>
    <!-- 监听器容器 -->
    <bean id="queueContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="connectionFactory" ref="connectionFactory" />
        <property name="destination" ref="queueDestination" />
        <property name="messageListener" ref="queueListener" />
    </bean>

测试类

ApplicationContext 

看DefaultMessageListenerContainer这个类的源码可以发现这个类实现了BeanNameAware, DisposableBean, SmartLifecycle 和InitializingBean这个四个接口。spring容器在初始化的时候,对于实现了BeanNameAware接口的bean可以知道这个bean自身的name;对于实现了DisposableBean接口的bean,在ApplicationContext 调用close()方法之后会执行destroy()方法;对于实现了SmartLifecycle接口的bean,会在所有bean加载和初始化完成之后调用这个bean的start()方法;对于实现了InitializingBean接口的bean,会在bean初始化的时候执行afterPropertiesSet()方法,afterPropertiesSet()方法比bean里面设置的init-method方法执行要早。

4.使用JmsMessagingTemplate

发送消息

public class MessagingTemplateSender {
	public static void main(String[] args) {
		JmsMessagingTemplate jmsMessagingTemplate = new JmsMessagingTemplate();
		jmsMessagingTemplate.setConnectionFactory(new ActiveMQConnectionFactory("admin", "admin", "tcp://localhost:61616"));
		jmsMessagingTemplate.convertAndSend(new ActiveMQQueue("queue1"), "aaa");
	}
}

convertAndSend方法的第二个参数payload(消息的主体)支持String,byte数组,Map<String,?>和可序列化的类

同步接收消息

import org.apache.activemq.ActiveMQConnectionFactory;
import org.springframework.jms.core.JmsMessagingTemplate;

public class MessagingTemplateReceiver {
	public static void main(String[] args) throws InterruptedException {
		JmsMessagingTemplate jmsMessagingTemplate = new JmsMessagingTemplate();
		jmsMessagingTemplate.setConnectionFactory(new ActiveMQConnectionFactory("admin", "admin", "tcp://localhost:61616"));
		while(true){
			Thread.sleep(1000);
			System.out.println(jmsMessagingTemplate.receive("queue1").getPayload());
		}
	}
}

得到的结果

5.集成Spring Boot

application.yml:

server:
  port: 8080
spring:
  activemq:
    broker-url:tcp://localhost:61616
    username:admin
    password:admin

pom:

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		
	    <dependency>
	       <groupId>org.springframework.boot</groupId>
	       <artifactId>spring-boot-starter-web</artifactId>
	    </dependency>
	
	    <!-- activemq-->
	    <dependency>
	           <groupId>org.springframework.boot</groupId>
	           <artifactId>spring-boot-starter-activemq</artifactId>
	    </dependency>
	</dependencies>

有了spring-boot-starter-activemq这个依赖之后springboot容器中会有一个JmsMessagingTemplate的对象,通过@Resource/@Autowire直接使用即可

发送消息

import javax.annotation.Resource;

import org.apache.activemq.command.ActiveMQQueue;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/sendToMq")
public class ActiveMqSenderController {

	@Resource
	private JmsMessagingTemplate jmsMessagingTemplate;
	
    @RequestMapping("/sendQueue")
	public void sendQueue(){
    	jmsMessagingTemplate.convertAndSend(new ActiveMQQueue("queue1"), "bbb");
	}
    
    @RequestMapping("/test")
	public @ResponseBody String test(){
		return "test";
	}
}

接收消息直接通过@JmsListener即可

import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;

@Component
public class Consummer {
	
	@JmsListener(destination="queue1",concurrency="")
	public void getMessage(String text){
		System.out.println("get message:"+text);
	}

}

启动springboot项目并访问http://localhost:8080/sendToMq/sendQueue

后台会得到如下:

二、高级特性

1.设置property和messageSelector的使用

在发送消息的时候给消息设置properties


    	ActiveMQTextMessage msg = new ActiveMQTextMessage();
    	msg.setText("aaa");
    	Map<String , Object> map = new HashMap<String, Object>();
    	map.put("name", "zhangsan");
    	map.put("age", 10);
    	msg.setProperties(map);
    	//也可以这样
    	//msg.setStringProperty("name", "zhangsan");
    	//msg.setIntProperty("age", 10);
    	jmsMessagingTemplate.convertAndSend(new ActiveMQQueue("queue1"), msg);

    	ActiveMQTextMessage msg1 = new ActiveMQTextMessage();
    	msg.setText("bbb");
    	msg.setStringProperty("name", "lisi");
    	msg.setIntProperty("age", 20);
    	jmsMessagingTemplate.convertAndSend(new ActiveMQQueue("queue1"), msg);

接收消息的时候设置消息选择器

	@JmsListener(destination="queue1",selector="age > 15 and name='lisi'")
	public void getMessage(String text){
		System.out.println("get message:"+text);
	}

或者不使用springboot注解在创建消费者的时候设置消息选择器


            consumer = session.createConsumer(destination,"age > 15 and name='lisi'");

启动后访问接口得到如下

第一条aaa的消息并没有得到

2.组合目的地(Composite Destinations)

有两种方案:

a.客户端


            destination = session.createQueue("queue1,queue2");

b.broker

在conf/activemq.xml的broker节点下,添加如下节点


                        <desinationInterceptors>
                                <virualDestinationInterceptors>
                                        <virtualDesinations>
                                                <compositeQueue name="queuetest">
                                                        <forwardTo>
                                                                <queue physicalName="queue1" />
                                                                <queue physicalName="queue2" />
                                                                <topic physicalName="topic1" />
                                                        </forwardTo>
                                               </compositeQueue>
                                       </virtualDestinations>
                               </virtualDestinationInterceptors>
                        </destinationInterceptors>

当发送到queuetest这个queue的时候就会发送给queue1,queue2和topic1这三个目的地

3.虚拟主题(Virtual Topic)

对于生产者就是创建一个以VirtualTopic.开头的topic

如:

Topic destination = session.createTopic("VirtualTopic.mytopic");

并设置持久化:

producer.setDeliveryMode(DeliveryMode.PERSISTENT);

对于消费者,可以创建多个Consumer.*.VirtualTopic.mytopic的queue

每一个不同目的地的消费者都可以收到全部消息,同一目的地的消费者共同收到全部消息

示例如下:

生产者:

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.apache.activemq.ActiveMQConnectionFactory;

public class VirtualSender {

	public static void main(String[] args) {
        // 连接工厂
        ConnectionFactory connectionFactory= new ActiveMQConnectionFactory(
               "admin",
                "admin",
                "tcp://localhost:61616");;
        //JMS 客户端到JMS Provider 的连接
        //发送消息的是生产者producer mq的服务器是提供者provider 接受消息的是消费者
        Connection connection = null;
        // Session: 一个发送或接收消息的线程
        //可以设置事务和确认方式
        Session session = null;
        // Destination :消息的目的地;消息发送给谁.
        //可以是一个topic 也可以是一个queue
        Destination destination;
        // MessageProducer:消息生产者
        MessageProducer producer;
        // 构造ConnectionFactory实例对象,此处采用ActiveMq的实现jar
        connectionFactory = new ActiveMQConnectionFactory(
               "admin",
                "admin",
                "tcp://localhost:61616");
        try {
            connection = connectionFactory.createConnection();
            // 启动
            connection.start();
            //createSession 第一个参数transacted 表示是否支持事务 
            //第二个参数 acknowledgeMode 有如下几种
            //1.AUTO_ACKNOWLEDGE 自动确认模式,不需客户端进行确认
            //2.CLIENT_ACKNOWLEDGE   客户端进行确认
            //客户端获得message之后需要进行message.acknowledge();
            //3.DUPS_OK_ACKNOWLEDGE  允许重复消息
            session = connection.createSession(Boolean.TRUE,
                    Session.AUTO_ACKNOWLEDGE);
            // 创建队列名为FirstQueue的目的地
//            destination = session.createQueue("queue1,queue2");
            destination = session.createTopic("VirtualTopic.TEST");
            // 创建将消息发送到该目的地的消息生产者
            producer = session.createProducer(destination);
            // 持久化模式 NON_PERSISTENT不持久化,PERSISTENT持久化
            producer.setDeliveryMode(DeliveryMode.PERSISTENT);
            producer.setPriority(4);
            for (int i = 0; i < 10; i++) {
                TextMessage message = session
                        .createTextMessage("第"+i+"条消息");
                // 发送消息到目的地方
                producer.send(message);
			}
            session.commit();
        } catch (Exception e) {
        	try {
        		if(null != session){
    				session.rollback();
        		}
			} catch (JMSException e1) {
				e1.printStackTrace();
			}
            e.printStackTrace();
        } finally {
            try {
                if (null != connection)
                    connection.close();
            } catch (Throwable ignore) {
            }
        }
    
	}
}

消费者:

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

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

public class VirtualReceiver {
	public static void main(String[] args) {
        ConnectionFactory connectionFactory;
        Connection connection = null;
        Session session;
        
        connectionFactory = new ActiveMQConnectionFactory(
                ActiveMQConnection.DEFAULT_USER,
                ActiveMQConnection.DEFAULT_PASSWORD,
                "tcp://localhost:61616");
        try {
            connection = connectionFactory.createConnection();
            connection.start();
            session = connection.createSession(Boolean.FALSE,
                    Session.AUTO_ACKNOWLEDGE);
            Destination destination1 = session.createQueue("Consumer.A.VirtualTopic.TEST");
            MessageConsumer consumer1 = session.createConsumer(destination1);
            consumer1.setMessageListener(new MessageListener() {
				public void onMessage(Message message) {
                  try {
					System.out.println("Consumer.A 收到消息:" + ((TextMessage)message).getText());
					} catch (JMSException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			});
            Destination destination2 = session.createQueue("Consumer.B.VirtualTopic.TEST");
            MessageConsumer consumer2 = session.createConsumer(destination2);
            consumer2.setMessageListener(new MessageListener() {
				public void onMessage(Message message) {
                  try {
					System.out.println("Consumer.B1 收到消息:" + ((TextMessage)message).getText());
					} catch (JMSException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			});
            MessageConsumer consumer3 = session.createConsumer(destination2);
            consumer3.setMessageListener(new MessageListener() {
				public void onMessage(Message message) {
                  try {
					System.out.println("Consumer.B2 收到消息:" + ((TextMessage)message).getText());
					} catch (JMSException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			});
            while(true){
            	Thread.sleep(1000);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != connection){
                    connection.close();
                }
            } catch (Throwable ignore) {
            }
        }
    }
}

先启动消费者在启动生产者得到结果:

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值