【问题标题】:ActiveMQ AMQP with JMS transformer leveraging spring IntegrationActiveMQ AMQP 与 JMS 转换器利用 spring 集成
【发布时间】:2017-05-24 01:48:16
【问题描述】:

我正在尝试利用 ActiveMQ 的 AMQP 和 JMS 转换器来启动和运行一个准系统应用程序。我的客户端库是 Spring Integration,但是,我无法在此配置中启动和运行基本示例。

关于 ActiveMQ 在 AMQP 上的 JMS 转换器的详细信息:http://activemq.apache.org/amqp.html

主要测试应用

@IntegrationComponentScan
@SpringBootApplication
public class SpringCloudStreamJmsActivemqSenderExampleApplication implements CommandLineRunner {

    @Bean
    public ConnectionFactory connectionFactory() {
        ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory();
        connectionFactory.setBrokerURL("tcp://localhost:61616");
        connectionFactory.setUserName("admin");
        connectionFactory.setPassword("admin");
        return connectionFactory;
    }

    @Bean
    public ConnectionFactory connectionFactoryAMQP() {
        ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory();
        connectionFactory.setBrokerURL("tcp://localhost:5672");
        connectionFactory.setUserName("admin");
        connectionFactory.setPassword("admin");
        return connectionFactory;
    }

    public static void main(String[] args) {
        SpringApplication.run(SpringCloudStreamJmsActivemqSenderExampleApplication.class, args);
    }

    @Autowired
    JmsGateway gateway;

    @Override
    public void run(String... strings) throws Exception {
        gateway.sendMessage("Hi");
    }

    @Bean(name = PollerMetadata.DEFAULT_POLLER)
    public PollerMetadata poller() {
        return Pollers.fixedDelay(1, TimeUnit.SECONDS).get();
    }

    @Bean(name = "outboundChannel")
    MessageChannel myOutBoundChannel() {
        return new QueueChannel();
    }

    @Bean(name = "inboundChannel")
    MessageChannel myInboundChannel() {
        return new QueueChannel();
    }

    @Bean(name = "errorChannel")
    MessageChannel myErrorChannel() {
        return new DirectChannel();
    }

    @Bean
    IntegrationFlow jmsInboundFlow() {
        return IntegrationFlows.from(Jms
                .inboundGateway(connectionFactoryAMQP())
                .destination("myCoolQueue")
                .errorChannel(myErrorChannel()))
                    .handle(this::print)
                .get();
    }

    @Bean
    IntegrationFlow jmsOutboundFlow() {
        return IntegrationFlows.from(myOutBoundChannel())
                .handle(Jms.outboundAdapter(connectionFactory())
                .destination("myCoolQueue"))
                .get();
    }

    @Bean
    IntegrationFlow customErrorFlow() {
        return IntegrationFlows.from(myErrorChannel())
                    .handle(this::printStackTrace)
                .get();
    }

    private void print(Message message) {
        System.out.println("Message payload: " + message.getPayload());
        //throw new RuntimeException("broke it");
    }

    private void printStackTrace(Message errorMessage) {
        ((ErrorMessage)errorMessage).getPayload().printStackTrace();
    }
}

消息网关

@MessagingGateway
interface JmsGateway {
    @Gateway(requestChannel = "outboundChannel")
    void sendMessage(String message);
}

ActiveMQ.xml

<transportConnectors>
    <transportConnector name="openwire" uri="tcp://0.0.0.0:0?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
    <transportConnector name="amqp" uri="amqp://0.0.0.0:0?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600&amp;transport.transformer=jms"/>
    <transportConnector name="mqtt" uri="mqtt://0.0.0.0:0?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
    <transportConnector name="ws" uri="ws://0.0.0.0:0?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
</transportConnectors>

日志输出

2017-01-09 08:42:26.158  INFO 24332 --- [  restartedMain] treamJmsActivemqSenderExampleApplication : Started SpringCloudStreamJmsActivemqSenderExampleApplication in 2.676 seconds (JVM running for 3.041)
2017-01-09 08:42:31.143  WARN 24332 --- [enerContainer-1] o.s.j.l.DefaultMessageListenerContainer  : Setup of JMS message listener invoker failed for destination 'myCoolQueue' - trying to recover. Cause: Disposed due to prior exception
2017-01-09 08:42:31.150 ERROR 24332 --- [enerContainer-1] o.s.j.l.DefaultMessageListenerContainer  : Could not refresh JMS Connection for destination 'myCoolQueue' - retrying using FixedBackOff{interval=5000, currentAttempts=0, maxAttempts=unlimited}. Cause: Cannot send, channel has already failed: tcp://127.0.0.1:5672
2017-01-09 08:42:36.155 ERROR 24332 --- [enerContainer-1] o.s.j.l.DefaultMessageListenerContainer  : Could not refresh JMS Connection for destination 'myCoolQueue' - retrying using FixedBackOff{interval=5000, currentAttempts=1, maxAttempts=unlimited}. Cause: Cannot send, channel has already failed: tcp://127.0.0.1:5672
2017-01-09 08:42:41.163 ERROR 24332 --- [enerContainer-1] o.s.j.l.DefaultMessageListenerContainer  : Could not refresh JMS Connection for destination 'myCoolQueue' - retrying using FixedBackOff{interval=5000, currentAttempts=2, maxAttempts=unlimited}. Cause: Cannot send, channel has already failed: tcp://127.0.0.1:5672

【问题讨论】:

  • 我认为这在额头上不起作用。您应该查看 Apache Qpid 项目以了解如何通过 JMS API 连接到 AMQP 1.0 代理。
  • 看看这里如何创建工厂stackoverflow.com/questions/39528325/…
  • 我不熟悉,但我认为您误解了变压器的作用。它不会更改 amqp 端口上的协议。看起来它将通过 AMQP(例如从 QPID Proton)发送的消息映射到 JMS 消息,以便 JMS 消费者(通过 OpenWire)使用它,反之亦然。
  • Jms 转换器将 AMQP 消息的标头映射到 JMS 消息标头,并将 AMQP 消息的正文映射到 JMS 正文,因为 amqp 和 jms 具有不同的结构和定义。基于 amqp 的 JMS

标签: jms activemq spring-integration amqp


【解决方案1】:

您必须通过两种方式更改您的 Bean 定义:

JNDI

@Bean
public ConnectionFactory connectionFactoryAMQP() {
    String factoryName = "myFactoryLookup";
    Properties props = new Properties();
    props.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.qpid.jms.jndi.JmsInitialContextFactory");
    props.setProperty("connectionfactory." + factoryName, "amqp://localhost:5672");
    props.put("property.connectionfactory." + factoryName + ".username", "admin");
    props.put("property.connectionfactory." + factoryName + ".password", "admin");
    InitialContext ic = new InitialContext(props);
    ConnectionFactory connectionFactory = (ConnectionFactory) ic.lookup(factoryName );
    return connectionFactory;
}

工厂

@Bean
public ConnectionFactory connectionFactoryAMQP() {
        org.apache.qpid.jms.JmsConnectionFactory connectionFactory = new JmsConnectionFactory();
        connectionFactory.setRemoteURI("amqp://localhost:5672");
        connectionFactory.setUsername("admin");
        connectionFactory.setPassword("admin");
    return connectionFactory;
}

添加这个依赖

<dependency> <groupId>org.apache.qpid</groupId> <artifactId>qpid-jms-client</artifactId> <version>0.9.0</version> </dependency>

在activemq.xml中添加端口

 <transportConnector name="amqp" uri="amqp://0.0.0.0:5672?transport.transformer=jms"/>

transport.transformer=jms 仅用于在 AMQP 传输和 ActiveMQ 之间的代理端将 JMS 消息从/到 AMQP 消息转换,当代理通过 AMQP 传输接收到 AMQP 消息时,它会从 AMQP 消息转换到 JMS 消息,当消息通过 AMQP 传输发送给消费者时,它会从 JMS 转换为 AMQP 消息。

【讨论】:

  • 非常感谢您提供工厂示例和 JMS 传输变压器说明。现在我的代码已经启动并顺利运行了。
【解决方案2】:

ActiveMQ 客户端只使用 ActiveMQ 本地协议 OpenWire,因此尝试将其连接到 AMQP 端口将不起作用,连接尝试将失败。您需要使用 AMQP 客户端连接到代理上的 AMQP 端口,以通过 AMQP 发送和接收消息。 Apache Qpid 项目有多个 AMQP v1.0 客户端可供选择。如果您想坚持使用 JMS 类型的客户端 API,那么 Qpid JMS 客户端就是您的最佳选择。

【讨论】:

  • Tim 这是否意味着 AMQP 设置上的 JMS 转换器选项不允许 JMS 客户端连接,但允许支持 JMS 消息格式?
猜你喜欢
  • 2014-08-23
  • 2016-11-23
  • 2015-06-06
  • 2016-05-08
  • 2015-12-24
  • 1970-01-01
  • 2020-10-21
  • 1970-01-01
  • 2011-02-23
相关资源
最近更新 更多