繁体   English   中英

Apache Camel JMS:尝试连接到队列时“不允许创建目标”

[英]Apache Camel JMS: “Not allowed to create destination” when trying to connect to a queue

我正在尝试在骆驼中设置一个从JMS队列读取消息的路由。

该应用程序使用Tibco,我不允许在此处发布任何数据,但是工厂和队列的路径遵循/ path / to / queueName:type的格式,其中type可以是qcf(队列连接工厂)和queue 。

我正在使用Spring-DSL,XML是:

<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
    <property name="environment">
        <props>
            <prop key="java.naming.factory.initial">...</prop>
            <prop key="java.naming.provider.url">...LDAP Server URL...</prop>
            <prop key="java.naming.referral">follow</prop>
            <prop key="java.naming.security.credentials">...</prop>
            <prop key="java.naming.security.principal">uid=...,ou=...,dc=...,dc=...</prop>
        </props>
    </property>
</bean>

<bean id="jmsQueueConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiTemplate" ref="jndiTemplate"/>
    <property name="jndiName" value="/path/to/queueConnectionFactory:qcf"/>
</bean>

<bean id="authenticatedConnectionFactory" class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">
    <property name="targetConnectionFactory" ref="jmsQueueConnectionFactory"/>
    <property name="username" value="..."/>
    <property name="password" value="..."/>
</bean>

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

<camelContext id="camelContext" xmlns="http://camel.apache.org/schema/spring">
    <route id="jmsRouteTest">
        <from uri="testjms:queue:/path/to/queue:queue" />
        <to uri="file:c:\inbox?fileName=jmsMessage.txt" />
    </route>
</camelContext>

当应用程序运行时,它会在日志中不断抛出以下行:

12:41:19:385 - WARN - DefaultMessageListenerContainer - Setup of JMS message listener invoker failed for destination 'path/to/queue:queue' - trying to recover. Cause: Not allowed to create destination
12:41:20:494 - INFO - DefaultMessageListenerContainer - Successfully refreshed JMS Connection

要注意的一件事是目标的第一个斜杠“ /”消失了,但是如果我从URI中删除“ queue:”,则会发生相同的错误,但是目标变为“ / path / to / queue:queue”。

我已经搜索了该错误,并在stackoverflow上找到了一个问题: 有谁确切知道javax.jms.InvalidDestinationException是什么:不允许创建目标方法?

为了确保配置正确,我创建了以下类(将完全相同的设置从Spring XML复制到该类):

import java.util.Properties;

import javax.jms.JMSException;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueReceiver;
import javax.jms.QueueSession;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import java.io.*;

public class Test {

public static void main(String[] args) throws Exception {
    Properties properties = new Properties();

    properties.put("java.naming.provider.url", "...LDAP Server URL...");
    properties.put("java.naming.factory.initial", "...");
    properties.put("java.naming.referral", "follow");
    properties.put("java.naming.security.principal", "uid=...,ou=...,dc=...,dc=...");
    properties.put("java.naming.security.credentials", "...");
    properties.put("JmsConnectionFactory", "/path/to/queueConnectionFactory:qcf");
    properties.put("JmsDestinationName", "/path/to/queue:queue");
    properties.put("JmsUserName", "...");
    properties.put("JmsPassword", "...");

    Context context = null;
    QueueConnection connection = null;
    QueueSession session = null;
    QueueReceiver receiver = null;

    context = new InitialContext(properties);

    Queue queue = (Queue) context.lookup((String) properties.get("JmsDestinationName"));
    QueueConnectionFactory queueConnectionFactory = (QueueConnectionFactory) context.lookup((String) properties.get("JmsConnectionFactory"));

    connection = queueConnectionFactory.createQueueConnection((String) properties.getProperty("JmsUserName"), 
                                                              properties.getProperty("JmsPassword"));

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

    connection.start();

    receiver = session.createReceiver(queue);

    while (true) {
        TextMessage message = (TextMessage) receiver.receive();

        System.out.println("Received: " + message.getText());

        BufferedReader bufferRead = new BufferedReader(new InputStreamReader(System.in));
        String s = bufferRead.readLine();

        if ("b".equals(s)) {
            break;
        }
    }

    connection.close();
}

}

通过此类,我可以读取队列中的消息。

有人遇到过这个问题吗?

如果您需要更多信息,请告诉我。

谢谢。

听起来您需要先让一些Tibco管理员来在Tibco消息代理上创建该队列。

谢谢您的帮助,但是解决方案非常简单。

我已经下载了要调试的源代码,并在名为DefaultMessageListenerContainer的Spring类中结束了该类,在会话中调用createConsumer方法时引发了异常。

这使我想到了Spring论坛中的一个主题http://forum.spring.io/forum/spring-projects/integration/jms/129634-dbus-jms-message-listener-javax-jms-jmssecurityexception-not-permitted

基本上,它说为了防止发生此错误,应该使用JNDI而不是session.createQueue()来获取目标。

然后,我搜索了在端点URI中使用JNDI名称的方法,并找到了http://camel.465427.n5.nabble.com/JMS-queue-JNDI-instead-of-physical-name-td494620.html

基本上,这表明需要目标解析器。 添加它可以解决该错误。

<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
    <property name="environment">
        <props>
            <prop...</prop>
        </props>
    </property>
</bean>

<bean id="jmsQueueConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiTemplate" ref="jndiTemplate"/>
    <property name="jndiName" value="..."/>
</bean>

<bean id="jmsDestinationResolver" class="org.springframework.jms.support.destination.JndiDestinationResolver">
    <property name="jndiTemplate" ref="jndiTemplate" />
    <property name="cache" value="true" />
</bean>

<bean id="testjms" class="org.apache.camel.component.jms.JmsComponent"> 
    <property name="connectionFactory" ref="jmsQueueConnectionFactory"/> 
    <property name="destinationResolver" ref="jmsDestinationResolver" />
</bean>

<camelContext id="camelContext" xmlns="http://camel.apache.org/schema/spring">
    <route id="testRoute">
        <from uri="testjms:jmsJNDIName?connectionFactory=jmsQueueConnectionFactory&amp;username=...&amp;password=..." />
        <to uri="file:C:\inbox" />
    </route>
</camelContext>

tl; dr-使用JNDI获取队列并指定目标解析器。

createQueue方法的名称具有误导性。 它并不是要真正创建队列本身,而仅仅是引用一个已经存在的队列的Queue对象(请参阅Javadoc )。

JMS不提供任何用于创建(非临时)队列的API。 这就是为什么您必须通过其他方式(通常是某些管理工具)创建队列,然后在JNDI中进行查找的原因。

但是某些JMS提供程序“滥用”此方法在需要时自动创建队列,从而使其无法移植到其他JMS提供程序。 这只是被记录在JMS 2.0被允许

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM