Java 为什么我对 QueueConnectionFactory 的 JNDI 查找返回 null?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1333221/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why is my JNDI lookup for a QueueConnectionFactory returning null?
提问by Simon Nickerson
I am trying to look up a QueueConnectionFactory
and Queue
via Geronimo's JNDI. The Queue
gets returned fine, but the QueueConnectionFactory
lookup always returns null. It doesn't throw a NamingException
, which is what I'd expect if the JNDI name was incorrect.
我正在尝试通过 Geronimo 的 JNDI查找QueueConnectionFactory
和Queue
。在Queue
获取返回正常,但QueueConnectionFactory
查找始终返回null。它不会抛出NamingException
,如果 JNDI 名称不正确,这就是我所期望的。
Can anyone see what I'm doing wrong? The test code below outputs:
谁能看到我做错了什么?下面的测试代码输出:
true false
import javax.jms.Queue;
import javax.jms.QueueConnectionFactory;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class JndiTest
{
private final static String QUEUE_NAME = "jca:/org.apache.geronimo.configs/activemq-ra/JCAAdminObject/SendReceiveQueue";
private final static String FACTORY_NAME = "jca:/org.apache.geronimo.configs/activemq-ra/JCAManagedConnectionFactory/DefaultActiveMQConnectionFactory";
public static void main(String[] args) throws NamingException
{
InitialContext ctx = new InitialContext();
QueueConnectionFactory factory = (QueueConnectionFactory) ctx.lookup(FACTORY_NAME);
Queue queue = (Queue)ctx.lookup(QUEUE_NAME);
System.out.println(factory == null);
System.out.println(queue == null);
}
}
In case it makes a difference: I've added openejb-client-3.0.1.jar, geronimo-ejb_3.0_spec-1.0.1.jar and activemq-core-4.1.2-G20090207.jar to my class path, and my jndi.properties file has the properties:
如果它有所不同:我已将 openejb-client-3.0.1.jar、geronimo-ejb_3.0_spec-1.0.1.jar 和 activemq-core-4.1.2-G20090207.jar 添加到我的类路径中,并且我的 jndi.properties 文件具有以下属性:
java.naming.factory.initial = org.apache.openejb.client.RemoteInitialContextFactory java.naming.provider.url = ejbd://127.0.0.1:4201
采纳答案by techzen
The reason why it is not throwing an exception is that - there is a ClassLoadException that comes when the resource is accessed.
它不抛出异常的原因是 - 访问资源时会出现 ClassLoadException。
And the reason why that is happening because the class : com.sun.jndi.url.jca.jcaURLContextFactory is being searched for by the ClassLoader called from ResourceManager.
之所以会发生这种情况,是因为从 ResourceManager 调用的 ClassLoader 正在搜索类:com.sun.jndi.url.jca.jcaURLContextFactory。
If you change the Factory name to some other name then you shall see the NamingException - but in the case of lookup , for Exceptions such as ClassNotFound/IllegalState - no exceptions are raised.
如果您将工厂名称更改为其他名称,那么您将看到 NamingException - 但在 lookup 的情况下,对于 ClassNotFound/IllegalState 等异常 - 不会引发异常。
The dependencies of ActiveMQ thus need to be analysed. Update1: One of the possible reasons is that the factory object can only be instantiated in a managed environment. Are you running your code as an application client?.
因此需要分析 ActiveMQ 的依赖关系。Update1:可能的原因之一是工厂对象只能在托管环境中实例化。您是否将代码作为应用程序客户端运行?
Update2: Some other pointers found for the cause of this behavior:
更新 2:针对此行为的原因找到了其他一些指针:
the openejb jndi implementation only exposes ejbs, not any other resources. If you have a j2ee app client, and you wish to use jms, you need to deploy a copy of the activemq adapter on the client. You can then use the j2ee java:comp/env context to find your stuff.
openejb jndi 实现只公开 ejb,不公开任何其他资源。如果您有 j2ee 应用程序客户端,并且希望使用 jms,则需要在客户端上部署 activemq 适配器的副本。然后您可以使用 j2ee java:comp/env 上下文来查找您的内容。
Found this on ActiveMQ site:
在 ActiveMQ 站点上找到了这个:
ActiveMQ's JNDI Implementation does NOT talk to the naming server. It's a stripped down version of a JNDI client that just allows to get Topics and Queues directly from a JMS instance. So, instead of supplying the naming server address, you have to supply the JMS server address.Most JNDI implementations use the java.naming.provider.url property to specify the naming server's address. ActiveMQ uses the brokerURLone. Using the java.naming.provider.url one instead will result in ActiveMQ trying to load the whole Broker.
ActiveMQ 的 JNDI 实现不与命名服务器对话。它是 JNDI 客户端的精简版,只允许直接从 JMS 实例获取主题和队列。因此,您不必提供命名服务器地址,而必须提供 JMS 服务器地址。大多数 JNDI 实现使用 java.naming.provider.url 属性来指定命名服务器的地址。ActiveMQ 使用brokerURL之一。使用 java.naming.provider.url 将导致 ActiveMQ 尝试加载整个 Broker。
See more on how to Connect using JNDI:
The initial context factory used in the explanation is: org.apache.activemq.jndi.ActiveMQInitialContextFactory
解释中使用的初始上下文工厂是:org.apache.activemq.jndi.ActiveMQInitialContextFactory
Some sample code to test with JNDI can be found here
可以在此处找到一些使用 JNDI 进行测试的示例代码
I wrote a simple java client - note below the provider url is the brokerURL that is being used.
我编写了一个简单的 Java 客户端 - 请注意提供者 URL 下方是正在使用的 brokerURL。
Properties props = new Properties();
props.put(Context.INITIAL_CONTEXT_FACTORY,
"org.apache.activemq.jndi.ActiveMQInitialContextFactory");
//props.put(Context.PROVIDER_URL,"vm://localhost");//Either this or below
props.put(Context.PROVIDER_URL,"tcp://localhost:65432");
props.put("queue.SendReceiveQueue",
"org.apache.geronimo.configs/activemq-ra/JCAAdminObject/SendReceiveQueue");
InitialContext context = new InitialContext(props);
QueueConnectionFactory connectionFactory = (QueueConnectionFactory)context.lookup
("ConnectionFactory");
Queue q = (Queue) context.lookup("SendReceiveQueue");
System.out.println("conn is : " + connectionFactory.getClass().getName());
System.out.println("queue is : " + q.getQueueName());
This program gives the output:
这个程序给出了输出:
conn is : org.apache.activemq.ActiveMQConnectionFactory queue is : org.apache.geronimo.configs/activemq-ra/JCAAdminObject/SendReceiveQueue
conn 是:org.apache.activemq.ActiveMQConnectionFactory 队列是:org.apache.geronimo.configs/activemq-ra/JCAAdminObject/SendReceiveQueue
回答by djna
There's two participants here, you're looking in JNDI for something. Somebody else had to put it there. I don't know the specifics of your environment but my approach to such problems is
这里有两个参与者,您正在 JNDI 中寻找某些东西。其他人不得不把它放在那里。我不知道您的环境的具体情况,但我解决此类问题的方法是
- explore the namespace - what's there? Do you have any JNDI browing tools?
- look carfeully in the logs for the service that is supposed to be registering with JNDI, does it report any errors?
- 探索命名空间 - 那里有什么?你有任何 JNDI 浏览工具吗?
- 仔细查看应该向 JNDI 注册的服务的日志,它是否报告任何错误?
回答by Antoine Claval
I have a somewhat equivalent configuration Tomcat/Geronimo J2EE jar / Geronimo JMS Jar / ActiveMQ 4 And i'm a little bit confused about your jndi.propertie file. Mine looks like this :
我有一个有点等效的配置 Tomcat/Geronimo J2EE jar / Geronimo JMS Jar / ActiveMQ 4 我对你的 jndi.propertie 文件有点困惑。我的看起来像这样:
java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory
java.naming.provider.url = tcp://localhost:61616
connectionFactoryNames = connectionFactory , TopicConnectionFactory
java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory
java.naming.provider.url = tcp://localhost:61616
connectionFactoryNames = connectionFactory , TopicConnectionFactory
The big difference is obviousely that your initial context is remote. Beside that, i must provide a connectionFactoryNames, or i get a NamingException.
最大的区别显然是您的初始上下文是远程的。除此之外,我必须提供一个 connectionFactoryNames,否则我会得到一个 NamingException。
回答by Grégory
I don't know why, but for me, using a context didn't work. It seems that the message is sent, but the onMessage of my consumer is not called.
我不知道为什么,但对我来说,使用上下文不起作用。好像是发送了消息,但是没有调用我的consumer的onMessage。
Using a context don't throw exception but don't work :
使用上下文不会抛出异常但不起作用:
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;
import javax.jms.TopicConnection;
import javax.jms.TopicConnectionFactory;
import javax.jms.TopicSession;
public class HelloClient {
public static void main(String[] args) throws Exception {
Properties ppt2 = new Properties();
ppt2.put(Context.INITIAL_CONTEXT_FACTORY,
"org.apache.activemq.jndi.ActiveMQInitialContextFactory");
ppt2.put(Context.PROVIDER_URL, "tcp://localhost:61616");
ppt2.put("topic.MessageDestinationTopic", "console.jms/TopicQueue/JCAAdminObject/MessageDestinationTopic");
Context ctx2 = new InitialContext(ppt2);
TopicConnectionFactory factory = (TopicConnectionFactory) ctx2.lookup("ConnectionFactory");
TopicConnection connection = factory.createTopicConnection();
TopicSession session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
Topic topic = (Topic) ctx2.lookup("MessageDestinationTopic");
MessageProducer producer = session.createProducer(topic);
TextMessage msg = session.createTextMessage();
msg.setText("this is a test message");
producer.send(msg);
producer.close();
session.close();
System.out.println("Message published. Please check application server's console to see the response from MDB");
ctx2.close();
System.exit(0);
}
}
Using the code below ( without context ) works well :
使用下面的代码(没有上下文)效果很好:
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;
import javax.jms.TopicConnection;
import javax.jms.TopicConnectionFactory;
import javax.jms.TopicSession;
public class HelloClient {
public static void main(String[] args) throws Exception {
TopicConnectionFactory factory = new org.apache.activemq.ActiveMQConnectionFactory("tcp://localhost:61616");
TopicConnection connection = factory.createTopicConnection();
TopicSession session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
Topic topic = session.createTopic("MessageDestinationTopic");
MessageProducer producer = session.createProducer(topic);
TextMessage msg = session.createTextMessage();
msg.setText("this is a test message");
producer.send(msg);
producer.close();
session.close();
System.out.println("Message published. Please check application server's console to see the response from MDB");
System.exit(0);
}
}