如何让 Spring 连接我的 JmsComponent [英] How to get Spring to wire my JmsComponent

查看:24
本文介绍了如何让 Spring 连接我的 JmsComponent的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个使用 Akka、Akka-Camel 和 Spring 进行配置的应用程序.应用程序需要充当针对各种应用程序服务器的独立 JMS 客户端,为此它需要使用 JNDI 设置 JMS 连接工厂.我正在用 jBoss 测试这个.我在 jBoss 5 和 6 上也有同样的问题(这似乎是客户端 Spring 问题,与 jBoss 无关).

I am writing an application using Akka, Akka-Camel and Spring for configuration. The application needs to act as a standalone JMS client against a variety of application servers, to which end it needs to set up the JMS connection factory using JNDI. I'm testing this with jBoss. I have the same problem with jBoss 5 and 6 (this seems to be a client-side Spring problem, not related to jBoss).

我正在用这个 xml 配置 Spring bean:

I am configuring the Spring beans with this xml:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:camel="http://camel.apache.org/schema/spring"
       xmlns:jee="http://www.springframework.org/schema/jee"
       xsi:schemaLocation="
         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
         http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
         http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
         ">

    <camelContext id="camel" trace="false" xmlns="http://camel.apache.org/schema/spring">
        <jmxAgent id="agent" disabled="true"/>
    </camelContext>

    <jee:jndi-lookup id="jmsConnectionFactory" jndi-name="ConnectionFactory">
        <jee:environment>
            java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
            java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
            java.naming.provider.url=jnp://192.168.0.109:1099
        </jee:environment>
    </jee:jndi-lookup>

    <bean name="jms" class="org.apache.camel.component.jms.JmsComponent">
        <property name="connectionFactory" ref="jmsConnectionFactory" />
    </bean>

</beans>

如您所见,我正在设置:

As you can see I'm setting up:

  • 通过 JNDI 初始化的 ConnectionFactory,称为 jmsConnectionFactory
  • 一个 JmsComponent,其 connectionFactory 属性设置为前一个 bean

使用此配置,我的应用程序在启动时失败:

With this configuration my app fails at startup with this:

java.lang.IllegalArgumentException: connectionFactory must be specified
    at org.apache.camel.util.ObjectHelper.notNull(ObjectHelper.java:294) ~[camel-core.jar:2.10.4]
    at org.apache.camel.component.jms.JmsConfiguration.createConnectionFactory(JmsConfiguration.java:1053) ~[camel-jms.jar:2.10.4]
    at org.apache.camel.component.jms.JmsConfiguration.getConnectionFactory(JmsConfiguration.java:416) ~[camel-jms.jar:2.10.4]
    at org.apache.camel.component.jms.JmsConfiguration.createListenerConnectionFactory(JmsConfiguration.java:1062) ~[camel-jms.jar:2.10.4]
    at org.apache.camel.component.jms.JmsConfiguration.getListenerConnectionFactory(JmsConfiguration.java:435) ~[camel-jms.jar:2.10.4]
    at org.apache.camel.component.jms.JmsConfiguration.configureMessageListenerContainer(JmsConfiguration.java:889) ~[camel-jms.jar:2.10.4]
    at org.apache.camel.component.jms.JmsConfiguration.createMessageListenerContainer(JmsConfiguration.java:379) ~[camel-jms.jar:2.10.4]

这来自 JmsConfiguration.java 中的这段代码:

This comes from this code in JmsConfiguration.java:

protected ConnectionFactory createConnectionFactory() {
    ObjectHelper.notNull(connectionFactory, "connectionFactory");
    return null;
}

因此看起来 Spring bean 初始化未能按照此处的指示关联/连接 bean(从之前粘贴的完整 XML Spring 配置中提取):

So it looks like the Spring beans initialization is failing to associate / wire the beans as instructed here (extracted from the full XML Spring configuration previously pasted):

    <bean name="jms" class="org.apache.camel.component.jms.JmsComponent">
        <property name="connectionFactory" ref="jmsConnectionFactory" />
    </bean>

我也尝试过创建一个中间 JmsConfiguration bean,并设置 JmsComponent 的配置属性,而不是直接设置 connectionFactory 属性,但我在两种设置中都得到了相同的结果.

I have also tried to create an intermediate JmsConfiguration bean, and setting the configuration property of the JmsComponent, instead of setting the connectionFactory property directly, but I get the same result in both setups.

顺便说一下,我可以通过代码连接 bean.我的意思是:

By the way, I can wire the beans by code alright. I mean that this:

val connFactory = springContext.getBean[javax.jms.ConnectionFactory]("jmsConnectionFactory", classOf[javax.jms.ConnectionFactory])
camelContext.addComponent("jms", JmsComponent.jmsComponentAutoAcknowledge(connFactory))

工作得很好.所以我知道我是从 JNDI 获取 ConnectionFactory 的,只是我无法使用正确的 Spring 配置将它连接到 XML 中.

works perfectly fine. So I know that I am getting the ConnectionFactory from JNDI, it's just that I can't hit the right Spring configuration to wire it in XML.

我需要这个应用程序无需重新编译即可配置,因此让 XML 工作对我来说是必须的.

I need this application to be very configurable without recompiling, so getting the XML to work is a must for me.

如果不清楚,问题是:如何让 Spring 设置我的 JmsComponent bean,并将其 connectionFactory 设置为 JNDI 获得的工厂?

In case it's not clear, the question is: How do I get Spring to set up my JmsComponent bean, with its connectionFactory set to the JNDI-obtained factory?

使用 Camel 的重点是它应该允许我交换这个组件,即使是另一个不同类型的组件.所以今天我使用 JMS,也许明天我将使用 TCP.这就是为什么能够在 XML 中定义所有内容很重要的原因.

The point of using Camel is that it should allow me to swap this component even for another of a different type. So today I'm using JMS, maybe tomorrow I'll be using TCP. This is why it would be important to be able to define everything in XML.

推荐答案

我认为问题在于 Akka 使用它自己的 CamelContext 而不是 Spring 配置中定义的.在早期版本的 Akka 中,似乎可以 设置 Akka 使用的上下文,但在最新版本中似乎不再可能.

I believe the problem is that Akka uses it's own CamelContext rather than the one defined in the Spring configuration. In earlier versions of Akka it seemed it was possible to set the context used by Akka, but that no longer appears to be possible in the latest versions.

我遇到了同样的问题,我在 Java(而不是 Scala)中使用基于注解的配置,并使用以下代码解决了这个问题:

I have encountered the same issue, I use annotation based configuration, in Java (rather than Scala), and have got around the issue using this code:

@Bean
public ActorSystem getCamelActorSystem(ConnectionFactory factory) {

    ActorSystem system = ActorSystem.create("some-system");

    Camel camel = CamelExtension.get(system);
    CamelContext camelContext = camel.context();
    camelContext.addComponent("jms", JmsComponent.jmsComponentAutoAcknowledge(factory));

    return system;
}

这会注入在别处定义的 ConnectionFactory 依赖项,并使用它来将 jms 组件添加到 Akka 使用的 camelContext.

This injects a ConnectionFactory dependency defined elsewhere and uses this to add the jms component to the camelContext used by Akka.

另一种解决方案可能是以某种方式扩展 CamelExtension 代码,以允许注入 camelContext 依赖项,就像以前一样.但是,我假设他们有充分的理由进行更改,因此我不理会它.我认为这是为了确保上下文不能更改,因此 Actor System 始终使用相同的 Camel 上下文,这是基于以下内容:

Another solution may be to extend the CamelExtension code in some way to allow the camelContext dependency to be injected, as was previously possible. However, I am assuming they had good reason for the change, and so am leaving it alone. I think it is so they can ensure the context cannot be changed so the Actor System always uses the same Camel context, this is based on the following:

一个 CamelExtension 只为每个 ActorSystem 加载一次,这使得在您的任何时候调用 CamelExtension 都是安全的获取与其关联的 Apache Camel 对象的代码.有每个 ActorSystem 一个 CamelContext 和一个 ProducerTemplate使用 CamelExtension.

One CamelExtension is only loaded once for every one ActorSystem, which makes it safe to call the CamelExtension at any point in your code to get to the Apache Camel objects associated with it. There is one CamelContext and one ProducerTemplate for every one ActorSystem that uses a CamelExtension.

http://doc.akka.io/docs/akka/current/scala/camel.html#CamelExtension

这篇关于如何让 Spring 连接我的 JmsComponent的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆