ActiveMQ发送List类型的消息

本文详细介绍了如何使用ActiveMQ发送和接收List类型的消息,包括生产者将List序列化,消费者通过反射技术获取数据。同时,讨论了不同消息类型的发送,如javabean、文件,并探讨了消息确认策略,如 AUTO_ACKNOWLEDGE 和 CLIENT_ACKNOWLEDGE 模式,强调了在Queue模式下手动确认消息的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、生产者代码(主要是把list序列化)

package springboot.activeMQ;

import org.apache.activemq.ActiveMQConnectionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jms.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;

public class Producer {
	private static final String url="tcp://127.0.0.1:61616";//服务地址,端口默认61616
	private static final String queueName="queue-test";//要创建的消息名称
	private static Logger log = LoggerFactory.getLogger(Producer.class);
	public static void main(String[] args) throws JMSException {
		//1.创建ConnectiongFactory,绑定地址
		ConnectionFactory factory=new ActiveMQConnectionFactory(url);
		//2.创建Connection
		Connection connection= factory.createConnection();
		//3.启动连接
		connection.start();
		//4.创建会话
		Session session=connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
		//5.创建一个目标
		Destination destination=session.createQueue(queueName);
		//6.创建一个生产者
		MessageProducer producer=session.createProducer(destination);
		List<String> list = new ArrayList<>();
		list.add("123");
		list.add("123");
		list.add("123");
		list.add("123");
		list.add("123");
		byte[] b = serialize(list);
		BytesMessage bb = session.createBytesMessage();
		bb.writeBytes(b);
		producer.send(bb);
		connection.close();
	}

	/**
	 * 列表序列化(用于Redis整存整取)
	 * @param value
	 * @return
	 */
	public static <T> byte[] serialize(List<T> value) {
		if (value == null) {
			throw new NullPointerException("Can't serialize null");
		}
		byte[] rv=null;
		ByteArrayOutputStream bos = null;
		ObjectOutputStream os = null;
		try {
			bos = new ByteArrayOutputStream();
			os = new ObjectOutputStream(bos);
			for(T obj : value){
				os.writeObject(obj);
			}
			os.writeObject(null);
			os.close();
			bos.close();
			rv = bos.toByteArray();
		} catch (IOException e) {
			throw new IllegalArgumentException("Non-serializable object", e);
		}
		return rv;
	}

}

二、消费者代码(由于没找到直接获取byte数组的方法,debug里发现content属性里的data便是之前发的数据,所以利用反射获取)

package springboot.activeMQ;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import javax.jms.*;

import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.util.ByteSequence;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Consumer{
	private static final String url="tcp://127.0.0.1:61616";//端口默认
	private static final String queueName="queue-test";//要消费的消息名称
	private static Logger log = LoggerFactory.getLogger(cs.class);
	public static void main(String[] args) throws JMSException {
		//1.创建ConnectiongFactory,绑定地址
		ConnectionFactory factory=new ActiveMQConnectionFactory(url);
		//2.创建Connection
		Connection connection= factory.createConnection();
		//3.启动连接
		connection.start();
		//4.创建会话
		Session session=connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
		//5.创建一个目标
		Destination destination=session.createQueue(queueName);
		//6.创建一个消费者
		MessageConsumer consumer=session.createConsumer(destination);
		//7.创建一个监听器
		consumer.setMessageListener(new MessageListener() {
			public void onMessage(Message arg0) {
				BytesMessage bm = (BytesMessage)arg0;
				Field field = null;
				Class<?> clazz = bm.getClass();
				for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
					try {
						field = clazz.getDeclaredField("content");
					} catch (Exception e) {
						// 这里甚么都不能抛出去。
						// 如果这里的异常打印或者往外抛,则就不会进入
					}
				}
				field.setAccessible(true);
				byte[] by = null;
				try {
					ByteSequence b = (ByteSequence) field.get(bm);
					by = b.getData();
				} catch (IllegalArgumentException e1) {
					e1.printStackTrace();
				} catch (IllegalAccessException e1) {
					e1.printStackTrace();
				}
				List<String> l = unserializeForList(by);
				System.out.println(l);
			}
		});
	}
    /**
     * 反序列化列表(用于Redis整存整取)
     * @param in
     * @return
     */
    public static <T> List<T> unserializeForList(byte[] in) {  
        List<T> list = new ArrayList<T>();  
        ByteArrayInputStream bis = null;  
        ObjectInputStream is = null;  
        try {  
            if(in != null) {  
                bis=new ByteArrayInputStream(in);  
                is=new ObjectInputStream(bis);  
                while (true) {  
                    T obj = (T) is.readObject();  
                    if(obj == null){  
                        break;  
                    }else{  
                        list.add(obj);  
                    }  
                }  
                is.close();  
                bis.close();  
            }  
        } catch (IOException e) {  
            log.warn("Caught IOException decoding %d bytes of data",  
                    in == null ? 0 : in.length, e);  
        } catch (ClassNotFoundException e) {  
            log.warn("Caught CNFE decoding %d bytes of data",  
                    in == null ? 0 : in.length, e);  
        } 
        return list;  
    }
}

三、发送数据的消息类型

            //纯字符串的数据
            session.createTextMessage();
            //序列化的对象
            session.createObjectMessage();
            //流,可以用来传递文件等
            session.createStreamMessage();
            //用来传递字节
            session.createBytesMessage();
            //这个方法创建出来的就是一个map,可以把它当作map来用
            session.createMapMessage();
            //这个方法,拿到的是javax.jms.Message,是所有message的接口
            session.createMessage();

(1)发送javabean对象类型,因为需要序列化,所以必须实现Serializable接口

            //使用createObjectMessage(),可以发送对象,前提是这个对象需要序列化,因为一切在网络在传输的,都是字节
            ObjectMessage obj = session.createObjectMessage();
            for(int i = 0 ; i < 100 ; i ++){
                Person p = new Person(i,"名字");
                obj.setObject(p);
                producer.send(obj);
            }

(2)接收javabean对象类型

            consumer.setMessageListener(new MessageListener() {
                @Override
                public void onMessage(Message message) {
                    try {
                        //强转为ObjectMessage,拿到对象后强转为Person
                        Person p = (Person) ((ObjectMessage)message).getObject();
                        System.out.println(p);
                    } catch (JMSException e) {
                        e.printStackTrace();
                    }
                }
            });

(3)发送文件类型,需要先读取文件,把读取到输入流中的子节数据放到writeBytes()里

            //使用createBytesMessage()创建消息
            BytesMessage bb = session.createBytesMessage();
            InputStream is = new FileInputStream("D:/test.txt");
            //开始读取信息
            byte[] b = new byte[5];//把所有的数据读取到这个字节当中
            //声明一个int存储每次读取到的数据
            int i = 0;
            //定义一个记录索引的变量
            int index = 0;
            //循环读取每个数据
            while((i=is.read())!=-1){//把读取的数据放到i中
                b[index]=(byte) i;
                index++;
            }
            //把字节数组转成字符串
            System.out.println(new String(b));
            //发送文件到消息中
            bb.writeBytes(new byte[]{2});
            //关闭流
            is.close();

(4)接收文件类型

                consumer.setMessageListener(new MessageListener() {
                @Override
                public void onMessage(Message message) {
                    BytesMessage bm = (BytesMessage)message;
                    FileOutputStream out = null;
                    try {
                        out = new FileOutputStream("d:/test.txt");
                    } catch (FileNotFoundException e2) {
                        e2.printStackTrace();
                    }
                    byte[] by = new byte[1024];
                    int len = 0 ;
                    try {
                        while((len = bm.readBytes(by))!= -1){
                            out.write(by,0,len);
                        }
                    } catch (JMSException | IOException e1) {
                        e1.printStackTrace();
                    }
                }
            });

四、确定消息能否成功处理

(1)AUTO_ACKNOWLEDGE,在之前创建一个session的时候,需要指定其事务,及消息的处理模式,当消息发送给消费者之后,就自动确认成功了,而不管消费者有没有处理成功,而一旦确认成功后,就会把队列里面的消息给清除掉,避免下一个消费者接收到同样的消息

session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

(2)CLIENT_ACKNOWLEDGE,如果消费者不确认消息,那么activemq将会把这条消息一直保留,直到有一个消费者确定了消息

session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);

在消费者接收到消息的时候,调用javax.jms.Message的acknowledge(),这样当消息处理成功之后,手动确认消息,如果不确定,activemq将会发给下一个消费者处理

                consumer.setMessageListener(new MessageListener() {
                @Override
                public void onMessage(Message message) {
                    try {
                        //获取到接收的数据
                        String text = ((TextMessage)message).getText();
                        System.out.println(text);
                        //确认接收,并成功处理了消息
                        message.acknowledge();
                    } catch (JMSException e) {
                        e.printStackTrace();
                    }
                }
            });

注:只在Queue队列模式中有效,在Topic主题模式即使不确认,也不会保存消息

Redis 和 ActiveMQ 是两种不同的技术栈,分别用于不同类型的队列管理和消息传递机制。然而,在某些情况下可能希望利用 Redis 的命令来间接影响或管理由 ActiveMQ 处理的消息队列。不过需要注意的是,两者之间并没有直接通过 Redis 命令操作 ActiveMQ 队列的方式[^1]。 对于想要结合这两种工具的情况,通常的做法是在应用程序层面上建立连接逻辑: - 使用 Java 或者其他支持的语言编写程序,一方面可以通过 JMS (Java Message Service) API 连接到 ActiveMQ发送/接收消息; - 另一方面也可以使用 Redis 客户端库来进行键值存储或其他形式的数据缓存处理; 如果目标是从 Redis 中触发事件进而作用于 ActiveMQ,则可以在监听到特定条件满足时(比如某个列表长度超过阈值),让应用服务器向 ActiveMQ 发送消息。 但是这并不意味着可以直接用 Redis 命令去操控 ActiveMQ 队列本身。为了实现更紧密集成的效果,考虑采用以下几种方法之一: - **桥接服务**:创建一个中间件作为桥梁,它能够响应来自 Redis 的变化并据此调用 ActiveMQ 接口。 - **复合架构设计**:重新评估系统需求,决定是否有必要引入额外组件或将现有功能迁移至单一平台之上,例如完全转向 Kafka 或 RocketMQ 等更加全面的消息代理方案[^2]。 ### 示例代码展示如何从 Redis 获取信号并向 ActiveMQ 发布消息 ```java // 导入必要的包... import org.apache.activemq.ActiveMQConnectionFactory; import redis.clients.jedis.Jedis; public class BridgeService { public static void main(String[] args) throws Exception { // 创建Jedis实例链接到本地运行的Redis服务器 try(Jedis jedis = new Jedis("localhost")) { String channelName = "myChannel"; while(true){ // 监听指定频道上的任何发布活动 List<String> messages = jedis.brpop(0,channelName); if(messages != null && !messages.isEmpty()){ System.out.println("Received message from Redis: "+messages.get(1)); // 将收到的信息转发给ActiveMQ sendToActiveMQ(messages.get(1)); } } } } private static void sendToActiveMQ(String msgContent)throws Exception{ ConnectionFactory connectionFactory=new ActiveMQConnectionFactory( brokerURL="tcp://localhost:61616"); try(Connection connection=connectionFactory.createConnection(); Session session=connection.createSession(false, Session.AUTO_ACKNOWLEDGE)){ Destination destination=session.createQueue("TESTQUEUE"); MessageProducer producer=session.createProducer(destination); TextMessage message=session.createTextMessage(msgContent); producer.send(message); System.out.println("Sent message to ActiveMQ queue."); }catch(Exception e){ throw e; } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值