Apache ActiveMQ Artemis 将 TextMessage 转换为 ObjectMessage

Apache ActiveMQ Artemis transform TextMessage to ObjectMessage

我有一个用例,我需要将消息从一种类型转换为另一种类型(即 TextMessage -> ObjectMessage)。

我发现在队列之间转移时有一个转换消息的选项。我已经按照文档中的说明实现了 Transformer 接口。

import org.apache.activemq.artemis.api.core.Message;
import org.apache.activemq.artemis.core.server.transformer.Transformer;
import javax.jms.ObjectMessage;
    
public class TypeTransformer implements Transformer {
    
    @Override
    public Message transform(Message message) {
        return message;
    }
}

但我现在开始意识到可能无法从 org.apache.activemq.artemis.api.core.Message 转换为 javax.jms.ObjectMessage?

这样对吗?是做不到还是有其他办法?

技术上应该可以将 javax.jms.TextMessage 转换为 javax.jms.ObjectMessage,但这可能很麻烦。以下是一些需要注意的重要事项:

  • javax.jms.TextMessagejavax.jms.ObjectMessageorg.apache.activemq.artemis.api.core.Message 都只是 接口 javax 版本是您在客户端上使用的版本,Message 是在代理上使用的版本。每种消息类型的数据在底层消息实现中的存储方式不同。
  • 您希望放入 ObjectMessage 的 Java 对象的 class 需要在经纪人的 class路径。这在正常情况下不需要,因为代理本身永远不会序列化或反序列化对象。
  • 您真的应该尽可能避免 ObjectMessageObjectMessage 对象依赖于 Java 序列化来编组和解组它们的对象负载。这个过程通常被认为是不安全的(而且很慢!),因为恶意负载可以利用主机系统。 Lots of CVEs have been created for this. For this reason, most JMS providers force users to explicitly whitelist packages that can be exchanged using ObjectMessage messages. For example, here's the related documentation for ActiveMQ Artemis. There are a number of other issues with using JMS ObjectMessage not related to security that you should read about.

假设您了解所有应该能够使用如下代码转换消息的内容:

import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

import org.apache.activemq.artemis.api.core.ICoreMessage;
import org.apache.activemq.artemis.api.core.Message;
import org.apache.activemq.artemis.api.core.SimpleString;
import org.apache.activemq.artemis.core.server.transformer.Transformer;

public class TypeTransformer implements Transformer {

   @Override
   public Message transform(Message message) {
      ICoreMessage coreMessage = message.toCore();
      try {
         // get the data from the TextMessage
         SimpleString mySimpleString = coreMessage.getBodyBuffer().readNullableSimpleString();
         if (mySimpleString == null) {
            // no text in the message so no transformation can be done
            return message;
         }
         String myString = mySimpleString.toString();

         // parse the data from the TextMessage and set it on the serializable object
         Serializable object = new MySerializable();         

         // turn serializable object into byte array and write it to the message
         ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
         ObjectOutputStream oos = new ObjectOutputStream(baos);
         oos.writeObject(object);
         oos.flush();
         byte[] data = baos.toByteArray();
         coreMessage.getBodyBuffer().clear();
         coreMessage.getBodyBuffer().writeInt(data.length);
         coreMessage.getBodyBuffer().writeBytes(data);
         coreMessage.setType(Message.OBJECT_TYPE);

         return coreMessage;
      } catch (Exception e) {
         e.printStackTrace();
         return message;
      }
   }
}