试图在ActiveMQ集群之间压缩jms ObjectMessages,序列化异常。如何强制执行ByteMessages?

时间:2017-01-27 15:41:21

标签: apache-camel jms

您好!

我正在开发一个大型ActiveMQ消息中心。许多应用程序通过我们的集线器向各种ActiveMQ集群发送消息,我们的工作是路由这些消息(就像邮政服务一样)。我们希望利用Camel将消息从一个ActiveMQ集群路由到另一个集群。我们希望Camel做的部分工作是压缩集群之间的消息。

但是,大多数消息都是作为ObjectMessages传递的,我们无法访问jar文件(更确切地说:对象文件中没有任何内容,也没有数据,我们只想压缩数据并将其移动到另一个代理)。就像邮政服务一样,我们也不感兴趣也不允许阅读这些信息,只需传递它们即可。

当我尝试从一个ActiveMQ代理读取,压缩消息并将其发送到另一个代理时,我将得到一个ClassCastException,我的序列化类在类路径中不存在。

我不希望Camel / ActiveMQ将对象序列化回Java对象,而是希望它只是将消息作为字节读取并压缩它们。 Camel是否有可能从ActiveMQ / JMS读取并认为它只是一个字节/流/ gobligook?

我得到的最接近的是指定jmsMessageType = Bytes,如下所示,但它不起作用。我试图在http://camel.apache.org/jms找到答案,但我找不到解决方案。

我试图将一个TextMessage排队,但它完美无缺。但是,这必须适用于每种JMS消息类型,包括ObjectMessages。

我使用的是Redhat A-MQ 6.3,Camel 2.17.0,位于Karaf 2.4.0,ActiveMQ 5.11.0。

如果你可以通过提供XML DSL示例版本/代码片段而不是Java DSL(我对Camel很新,并且还没有习惯)来帮助我,那么你将获得“额外积分”(或者至少我会非常高兴)在这些之间进行翻译),但任何帮助都是张开双臂接受的!

非常感谢您提供的任何想法或解决方案!

我的骆驼文件是

<beans xmlns="http://www.springframework.org/schema/beans"
       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-3.0.xsd
       http://camel.apache.org/schema/spring
       http://camel.apache.org/schema/spring/camel-spring.xsd">

  <bean id="jmsone" class="org.apache.camel.component.jms.JmsComponent">
    <property name="connectionFactory">
      <bean class="org.apache.activemq.ActiveMQConnectionFactory">
        <property name="brokerURL" value="vm://localhost" />
        <property name="userName" value="admin" />
        <property name="password" value="admin" />
      </bean>
    </property>
  </bean>

  <bean id="jmstwo" class="org.apache.camel.component.jms.JmsComponent">
    <property name="connectionFactory">
      <bean class="org.apache.activemq.ActiveMQConnectionFactory">
        <property name="brokerURL" value="tcp://numbertwo:61616" />
        <property name="userName" value="admin" />
        <property name="password" value="admin" />
      </bean>
    </property>
  </bean>

  <camelContext xmlns="http://camel.apache.org/schema/spring">

    <dataFormats>
      <gzip id="compressor"/>
    </dataFormats>

    <route id="queueToOtherBroker">
      <from uri="jmsone:andersPanders?jmsMessageType=Bytes" />
      <marshal ref="compressor" />
      <to uri="jmstwo:olleBandola" />
    </route>
  </camelContext>
</beans>

地址numberone和numbertwo是Docker容器,连接不是问题,他们可以互相交谈。

这是完整的例外

2017-01-27 14:54:43,003 | WARN  | r[andersPanders] | EndpointMessageListener          | rg.apache.camel.util.CamelLogger  213 | 192 - org.apache.camel.camel-core - 2.17.0.redhat-630187 | Execution of JMS message listener failed. Caused by: [org.apache.camel.RuntimeCamelException - Failed to extract body due to: javax.jms.JMSException: Failed to build body from content. Serializable class not available to broker. Reason: java.lang.ClassNotFoundException: Anders not found by org.apache.activemq.activemq-osgi [162]. Message: ActiveMQObjectMessage {commandId = 5, responseRequired = true, messageId = ID:VeryGoodTea-42317-1485528882333-1:1:1:1:1, originalDestination = null, originalTransactionId = null, producerId = ID:VeryGoodTea-42317-1485528882333-1:1:1:1, destination = queue://andersPanders, transactionId = null, expiration = 0, timestamp = 1485528882925, arrival = 0, brokerInTime = 1485528882928, brokerOutTime = 1485528882944, correlationId = null, replyTo = null, persistent = true, type = null, priority = 4, groupID = null, groupSequence = 0, targetConsumerId = null, compressed = false, userID = null, content = org.apache.activemq.util.ByteSequence@57958b, marshalledProperties = null, dataStructure = null, redeliveryCounter = 0, size = 1109, properties = null, readOnlyProperties = true, readOnlyBody = true, droppable = false, jmsXGroupFirstForConsumer = false}]
org.apache.camel.RuntimeCamelException: Failed to extract body due to: javax.jms.JMSException: Failed to build body from content. Serializable class not available to broker. Reason: java.lang.ClassNotFoundException: Anders not found by org.apache.activemq.activemq-osgi [162]. Message: ActiveMQObjectMessage {commandId = 5, responseRequired = true, messageId = ID:VeryGoodTea-42317-1485528882333-1:1:1:1:1, originalDestination = null, originalTransactionId = null, producerId = ID:VeryGoodTea-42317-1485528882333-1:1:1:1, destination = queue://andersPanders, transactionId = null, expiration = 0, timestamp = 1485528882925, arrival = 0, brokerInTime = 1485528882928, brokerOutTime = 1485528882944, correlationId = null, replyTo = null, persistent = true, type = null, priority = 4, groupID = null, groupSequence = 0, targetConsumerId = null, compressed = false, userID = null, content = org.apache.activemq.util.ByteSequence@57958b, marshalledProperties = null, dataStructure = null, redeliveryCounter = 0, size = 1109, properties = null, readOnlyProperties = true, readOnlyBody = true, droppable = false, jmsXGroupFirstForConsumer = false}
    at org.apache.camel.component.jms.JmsBinding.extractBodyFromJms(JmsBinding.java:160)[206:org.apache.camel.camel-jms:2.17.0.redhat-630187]
    at org.apache.camel.component.jms.JmsMessage.createBody(JmsMessage.java:236)[206:org.apache.camel.camel-jms:2.17.0.redhat-630187]
    at org.apache.camel.impl.MessageSupport.getBody(MessageSupport.java:47)[192:org.apache.camel.camel-core:2.17.0.redhat-630187]
    at org.apache.camel.impl.DefaultUnitOfWork.<init>(DefaultUnitOfWork.java:90)[192:org.apache.camel.camel-core:2.17.0.redhat-630187]
    at org.apache.camel.impl.DefaultUnitOfWork.<init>(DefaultUnitOfWork.java:72)[192:org.apache.camel.camel-core:2.17.0.redhat-630187]
    at org.apache.camel.impl.DefaultUnitOfWorkFactory.createUnitOfWork(DefaultUnitOfWorkFactory.java:34)[192:org.apache.camel.camel-core:2.17.0.redhat-630187]
    at org.apache.camel.processor.CamelInternalProcessor$UnitOfWorkProcessorAdvice.createUnitOfWork(CamelInternalProcessor.java:683)[192:org.apache.camel.camel-core:2.17.0.redhat-630187]
    at org.apache.camel.processor.CamelInternalProcessor$UnitOfWorkProcessorAdvice.before(CamelInternalProcessor.java:651)[192:org.apache.camel.camel-core:2.17.0.redhat-630187]
    at org.apache.camel.processor.CamelInternalProcessor$UnitOfWorkProcessorAdvice.before(CamelInternalProcessor.java:628)[192:org.apache.camel.camel-core:2.17.0.redhat-630187]
    at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:144)[192:org.apache.camel.camel-core:2.17.0.redhat-630187]
    at org.apache.camel.util.AsyncProcessorHelper.process(AsyncProcessorHelper.java:109)[192:org.apache.camel.camel-core:2.17.0.redhat-630187]
    at org.apache.camel.processor.DelegateAsyncProcessor.process(DelegateAsyncProcessor.java:91)[192:org.apache.camel.camel-core:2.17.0.redhat-630187]
    at org.apache.camel.component.jms.EndpointMessageListener.onMessage(EndpointMessageListener.java:112)[206:org.apache.camel.camel-jms:2.17.0.redhat-630187]
    at org.springframework.jms.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:555)[205:org.apache.servicemix.bundles.spring-jms:3.2.16.RELEASE_2]
    at org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:515)[205:org.apache.servicemix.bundles.spring-jms:3.2.16.RELEASE_2]
    at org.springframework.jms.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:485)[205:org.apache.servicemix.bundles.spring-jms:3.2.16.RELEASE_2]
    at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.doReceiveAndExecute(AbstractPollingMessageListenerContainer.java:325)[205:org.apache.servicemix.bundles.spring-jms:3.2.16.RELEASE_2]
    at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:263)[205:org.apache.servicemix.bundles.spring-jms:3.2.16.RELEASE_2]
    at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1103)[205:org.apache.servicemix.bundles.spring-jms:3.2.16.RELEASE_2]
    at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1095)[205:org.apache.servicemix.bundles.spring-jms:3.2.16.RELEASE_2]
    at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:992)[205:org.apache.servicemix.bundles.spring-jms:3.2.16.RELEASE_2]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)[:1.8.0_121]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)[:1.8.0_121]
    at java.lang.Thread.run(Thread.java:745)[:1.8.0_121]
Caused by: javax.jms.JMSException: Failed to build body from content. Serializable class not available to broker. Reason: java.lang.ClassNotFoundException: Anders not found by org.apache.activemq.activemq-osgi [162]
    at org.apache.activemq.util.JMSExceptionSupport.create(JMSExceptionSupport.java:36)[162:org.apache.activemq.activemq-osgi:5.11.0.redhat-630187]
    at org.apache.activemq.command.ActiveMQObjectMessage.getObject(ActiveMQObjectMessage.java:208)[162:org.apache.activemq.activemq-osgi:5.11.0.redhat-630187]
    at org.apache.camel.component.jms.JmsBinding.extractBodyFromJms(JmsBinding.java:135)[206:org.apache.camel.camel-jms:2.17.0.redhat-630187]
... 23 more
Caused by: java.lang.ClassNotFoundException: Anders not found by org.apache.activemq.activemq-osgi [162]
    at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1556)[org.apache.felix.framework-4.4.1.jar:]
    at org.apache.felix.framework.BundleWiringImpl.access$400(BundleWiringImpl.java:77)[org.apache.felix.framework-4.4.1.jar:]
    at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:1993)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)[:1.8.0_121]
    at java.lang.Class.forName0(Native Method)[:1.8.0_121]
    at java.lang.Class.forName(Class.java:348)[:1.8.0_121]
    at org.apache.activemq.util.ClassLoadingAwareObjectInputStream.load(ClassLoadingAwareObjectInputStream.java:140)[162:org.apache.activemq.activemq-osgi:5.11.0.redhat-630187]
    at org.apache.activemq.util.ClassLoadingAwareObjectInputStream.resolveClass(ClassLoadingAwareObjectInputStream.java:55)[162:org.apache.activemq.activemq-osgi:5.11.0.redhat-630187]
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1819)[:1.8.0_121]
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1713)[:1.8.0_121]
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1986)[:1.8.0_121]
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1535)[:1.8.0_121]
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:422)[:1.8.0_121]
    at org.apache.activemq.command.ActiveMQObjectMessage.getObject(ActiveMQObjectMessage.java:206)[162:org.apache.activemq.activemq-osgi:5.11.0.redhat-630187]
    ... 24 more

Anders只是我用来测试压缩的一个类。

我在groovy的测试程序:

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

class Anders implements Serializable {
      String name = "Anders Andersson"
      int age=120
}

def brokerUrl = 'tcp://localhost:61616'
def queue = 'andersPanders'

def reader = new BufferedReader(new InputStreamReader(System.in))

new ActiveMQConnectionFactory(brokerURL: brokerUrl, userName: "admin", password: "admin").createConnection().with {
  start()
  createSession(false, Session.AUTO_ACKNOWLEDGE).with {
   def message = createObjectMessage(new Anders())
   createProducer().send(createQueue(queue), message)
  }
  close()
}

1 个答案:

答案 0 :(得分:1)

免责声明:ObjectMessage是JMS中的反模式,因为它引入了紧耦合,并且存在安全问题。

也就是说,这个解决方案只适用于ActiveMQ,而不适用于通用的JMS:

                

<route id="routeme">
  <from uri="activemq:inputqueue?mapJmsMessage=false" />
  <setBody>
    <simple>${body.getContent().getData()}</simple>
  </setBody>
  <marshal ref="compressor"/>
  <to uri="activemq:outputqueue" />
</route>

mapJmsMessage=false使Camel避免读取实际的对象并将正文保持为ActiveMQObjectMessage。使用该对象,您实际上可以获得支持ObjectMessage的byte[]。上述路线的输出为BytesMessage