问题描述
我正在尝试向嵌入在JBoss EAP 7.2中的远程ActiveMQ Artemis队列发送JMS消息.我在standalone-full.xml
中定义了以下内容:
I am trying to send a JMS message to remote ActiveMQ Artemis queue that is embedded in JBoss EAP 7.2. I have defined the following in standalone-full.xml
:
- 远程连接器
- 池连接工厂
- 远程绑定
<subsystem xmlns="urn:jboss:domain:messaging-activemq:4.0">
<server name="default">
<journal pool-files="10"/>
<security-setting name="#">
<role name="guest" send="true" consume="true" create-non-durable-queue="true" delete-non-durable-queue="true"/>
</security-setting>
<address-setting name="#" dead-letter-address="jms.queue.DLQ" expiry-address="jms.queue.ExpiryQueue" max-size-bytes="10485760" page-size-bytes="2097152" message-counter-history-day-limit="10"/>
<http-connector name="http-connector" socket-binding="http" endpoint="http-acceptor"/>
<http-connector name="http-connector-throughput" socket-binding="http" endpoint="http-acceptor-throughput">
<param name="batch-delay" value="50"/>
</http-connector>
<remote-connector name="ImportantMessages-remote" socket-binding="ImportantMessages-remote"/>
<in-vm-connector name="in-vm" server-id="0">
<param name="buffer-pooling" value="false"/>
</in-vm-connector>
<http-acceptor name="http-acceptor" http-listener="default"/>
<http-acceptor name="http-acceptor-throughput" http-listener="default">
<param name="batch-delay" value="50"/>
<param name="direct-deliver" value="false"/>
</http-acceptor>
<in-vm-acceptor name="in-vm" server-id="0">
<param name="buffer-pooling" value="false"/>
</in-vm-acceptor>
<jms-queue name="TestQueue" entries="java:/jms/queue/TestQueue"/>
<jms-queue name="ExpiryQueue" entries="java:/jms/queue/ExpiryQueue"/>
<jms-queue name="DLQ" entries="java:/jms/queue/DLQ"/>
<connection-factory name="InVmConnectionFactory" entries="java:/ConnectionFactory" connectors="in-vm"/>
<connection-factory name="RemoteConnectionFactory" entries="java:jboss/exported/jms/RemoteConnectionFactory" connectors="http-connector"/>
<pooled-connection-factory name="activemq-ra" entries="java:/JmsXA java:jboss/DefaultJMSConnectionFactory" connectors="in-vm" transaction="xa"/>
<pooled-connection-factory name="ImportantMessages-remote" entries="java:/jms/remoteIM" connectors="ImportantMessages-remote"/>
</server>
</subsystem>
<subsystem xmlns="urn:wildfly:microprofile-config-smallrye:1.0"/>
<subsystem xmlns="urn:wildfly:microprofile-health-smallrye:1.0" security-enabled="false"/>
<subsystem xmlns="urn:wildfly:microprofile-opentracing-smallrye:1.0"/>
<subsystem xmlns="urn:jboss:domain:naming:2.0">
<bindings>
<external-context name="java:global/remoteContext" module="org.apache.activemq.artemis" class="javax.naming.InitialContext">
<environment>
<property name="java.naming.factory.initial" value="org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory"/>
<property name="java.naming.provider.url" value="tcp://127.0.0.1:61616"/>
<property name="queue.ImportantMessages" value="ImportantMessages"/>
</environment>
</external-context>
<lookup name="java:/ImportantMessages" lookup="java:global/remoteContext/ImportantMessages"/>
</bindings>
<remote-naming/>
</subsystem>
下面是我的客户程序:
public void sendObjectMessage() {
Properties initialProperties = new Properties();
initialProperties.put(InitialContext.INITIAL_CONTEXT_FACTORY, "org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory");
initialProperties.put(InitialContext.PROVIDER_URL, "tcp://127.0.0.1:61616");
try {
context = new InitialContext(initialProperties);
factory = (QueueConnectionFactory) context.lookup("java:/jms/remoteIM");
destination = (Queue) context.lookup("java:global/remoteContext/ImportantMessages");
connection = factory.createConnection();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
producer = session.createProducer(destination);
EventMessage eventMessage = new EventMessage("1", "Message from FirstClient");
ObjectMessage objectMessage = session.createObjectMessage();
objectMessage.setObject(eventMessage);
connection.start();
producer.send(objectMessage);
System.out.println(this.getClass().getName() + "has sent a message : " + eventMessage);
} catch (NamingException e) {
e.printStackTrace();
} catch (JMSException e) {
e.printStackTrace();
} finally {
if (context != null) {
try {
context.close();
} catch (NamingException ex) {
ex.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (JMSException ex) {
ex.printStackTrace();
}
}
}
}
我收到以下异常:
javax.naming.NamingException: scheme java not recognized
at org.apache.activemq.artemis.jndi.ReadOnlyContext.lookup(ReadOnlyContext.java:222)
at javax.naming.InitialContext.lookup(Unknown Source)
at com.example.demo.sender.FirstClient.sendObjectMessage(FirstClient.java:41)
at com.example.demo.controller.MessagingController.sendMessage(MessagingController.java:19)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:888)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:526)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:367)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:860)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1591)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Unknown Source)
有人可以建议我我在这里做什么错吗?
Can anyone suggest me what wrong I am doing here?
推荐答案
要将JMS消息发送到嵌入在JBoss EAP中的远程ActiveMQ Artemis队列,可以使用默认的standalone-full.xml
.您不需要设置远程连接器,池连接工厂,或远程绑定.您只需要使用JBoss EAP JNDI上下文从客户端中查找jms/RemoteConnectionFactory
.需要明确的是,当ActiveMQ Artemis嵌入JBoss EAP远程客户端时,使用JBoss EAP JNDI上下文而不是ActiveMQ Artemis JNDI上下文,因为EAP本身负责所有JNDI操作.
In order to send a JMS message to remote ActiveMQ Artemis queue that is embedded in JBoss EAP you can use the default standalone-full.xml
. You don't need to set up a remote connector, pooled connection factory, or remote binding. You simply need to lookup jms/RemoteConnectionFactory
from your client using JBoss EAP JNDI context. To be clear, when ActiveMQ Artemis is embedded in JBoss EAP remote clients use the JBoss EAP JNDI context not the ActiveMQ Artemis JNDI context since EAP itself is in charge of all JNDI operations.
您的客户正在使用ActiveMQ Artemis JNDI上下文:
Your client is using the ActiveMQ Artemis JNDI context:
initialProperties.put(InitialContext.INITIAL_CONTEXT_FACTORY, "org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory");
initialProperties.put(InitialContext.PROVIDER_URL, "tcp://127.0.0.1:61616");
这是不正确的.您应该改用这个:
This is incorrect. You should be using this instead:
initialProperties.put(InitialContext.INITIAL_CONTEXT_FACTORY, "org.wildfly.naming.client.WildFlyInitialContextFactory");
initialProperties.put(InitialContext.PROVIDER_URL, "http-remoting://127.0.0.1:8080");
注意:您也可以在此处使用org.jboss.naming.remote.client.InitialContextFactory
,因为该类也随JBoss EAP 7.2一起提供.但是,实际上包含该类是为了与旧版客户端向后兼容.
Note: You could also use org.jboss.naming.remote.client.InitialContextFactory
here because that class is also shipped with JBoss EAP 7.2. However, this class is really included for backwards compatibility with legacy clients.
然后您的客户端正在尝试查找您在standalone-full.xml
中配置的pooled-connection-factory
:
Then your client is trying to lookup the pooled-connection-factory
you configured in standalone-full.xml
:
factory = (QueueConnectionFactory) context.lookup("java:/jms/remoteIM");
这也是不正确的.在与JBoss EAP相同的JVM中运行的客户端只能使用pooled-connection-factory
(例如,需要发送消息的MDB).您不能简单地从远程客户端中查找它并期望得到池化.那不是它的工作原理.您应该改为这样做:
This is also incorrect. A pooled-connection-factory
can only be used by clients running in the same JVM as JBoss EAP (e.g. an MDB which needs to send a message). You can't simply look it up from a remote client and expect to get pooling. That's not how it works. You should be doing this instead:
factory = (QueueConnectionFactory) context.lookup("jms/RemoteConnectionFactory");
这将使用名为RemoteConnectionFactory
的standalone-full.xml
中的默认connection-factory
.
This will use the default connection-factory
in standalone-full.xml
named RemoteConnectionFactory
.
然后,您正在查找甚至在消息传递子系统(即java:global/remoteContext/ImportantMessages
)中未定义的队列.您出于某种原因显然已经在external-context
中对其进行了配置.对于EAP,这是错误的.您应该在standalone-full.xml
:
Then you're looking up a queue which isn't even defined in the messaging subsystem (i.e. java:global/remoteContext/ImportantMessages
). You've apparently configured it in an external-context
for some reason. This is wrong for EAP. You should define this in your standalone-full.xml
:
<jms-queue name="ImportantMessages" entries="java:jboss/exported/ImportantMessages"/>
然后在您的客户端中使用它:
And then use this in your client:
destination = (Queue) context.lookup("ImportantMessages");
最终,这是standalone-full.xml
中的消息传递子系统应如下所示:
Ultimately, this is what your messaging subsystem in standalone-full.xml
should look like:
<subsystem xmlns="urn:jboss:domain:messaging-activemq:4.0">
<server name="default">
<journal pool-files="10"/>
<security-setting name="#">
<role name="guest" send="true" consume="true" create-non-durable-queue="true" delete-non-durable-queue="true"/>
</security-setting>
<address-setting name="#" dead-letter-address="jms.queue.DLQ" expiry-address="jms.queue.ExpiryQueue" max-size-bytes="10485760" page-size-bytes="2097152" message-counter-history-day-limit="10"/>
<http-connector name="http-connector" socket-binding="http" endpoint="http-acceptor"/>
<http-connector name="http-connector-throughput" socket-binding="http" endpoint="http-acceptor-throughput">
<param name="batch-delay" value="50"/>
</http-connector>
<in-vm-connector name="in-vm" server-id="0">
<param name="buffer-pooling" value="false"/>
</in-vm-connector>
<http-acceptor name="http-acceptor" http-listener="default"/>
<http-acceptor name="http-acceptor-throughput" http-listener="default">
<param name="batch-delay" value="50"/>
<param name="direct-deliver" value="false"/>
</http-acceptor>
<in-vm-acceptor name="in-vm" server-id="0">
<param name="buffer-pooling" value="false"/>
</in-vm-acceptor>
<jms-queue name="ImportantMessages" entries="java:jboss/exported/ImportantMessages"/>
<jms-queue name="ExpiryQueue" entries="java:/jms/queue/ExpiryQueue"/>
<jms-queue name="DLQ" entries="java:/jms/queue/DLQ"/>
<connection-factory name="InVmConnectionFactory" entries="java:/ConnectionFactory" connectors="in-vm"/>
<connection-factory name="RemoteConnectionFactory" entries="java:jboss/exported/jms/RemoteConnectionFactory" connectors="http-connector"/>
<pooled-connection-factory name="activemq-ra" entries="java:/JmsXA java:jboss/DefaultJMSConnectionFactory" connectors="in-vm" transaction="xa"/>
</server>
</subsystem>
您不需要配置的external-context
.
最后,这就是客户的最终外观:
Lastly, this is what your client should ultimately look like:
public void sendObjectMessage() {
Properties initialProperties = new Properties();
initialProperties.put(InitialContext.INITIAL_CONTEXT_FACTORY, "org.wildfly.naming.client.WildFlyInitialContextFactory");
initialProperties.put(InitialContext.PROVIDER_URL, "http-remoting://127.0.0.1:8080");
try {
context = new InitialContext(initialProperties);
factory = (QueueConnectionFactory) context.lookup("jms/RemoteConnectionFactory");
destination = (Queue) context.lookup("ImportantMessages");
connection = factory.createConnection();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
producer = session.createProducer(destination);
EventMessage eventMessage = new EventMessage("1", "Message from FirstClient");
ObjectMessage objectMessage = session.createObjectMessage();
objectMessage.setObject(eventMessage);
connection.start();
producer.send(objectMessage);
System.out.println(this.getClass().getName() + "has sent a message : " + eventMessage);
} catch (NamingException e) {
e.printStackTrace();
} catch (JMSException e) {
e.printStackTrace();
} finally {
if (context != null) {
try {
context.close();
} catch (NamingException ex) {
ex.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (JMSException ex) {
ex.printStackTrace();
}
}
}
}
JBoss EAP提供了许多"quickstart"应用程序,以演示如何使用其功能.这是 JMS"Hello World"快速入门,可能对您有所帮助.
JBoss EAP has a bunch of "quickstart" applications available to demonstrate how to use its features. Here is the JMS "Hello World" quickstart which you might find useful for reference.
如果要使用Maven构建客户端应用程序,则应使用以下依赖项:
If you're building your client application with Maven then this is the dependency you should be using:
<dependency>
<groupId>org.jboss.eap</groupId>
<artifactId>wildfly-jms-client-bom</artifactId>
<type>pom</type>
</dependency>
此外,请记住,默认情况下,嵌入在JBoss EAP 7.2中的ActiveMQ Artemis是安全的,因此您将需要禁用消息传递子系统中的安全性(例如,使用<security enabled="false"/>
)或将用户添加到ApplicationRealm
中(例如,通过bin/add-user.sh
脚本)并在创建您的连接.
Also, keep in mind that ActiveMQ Artemis embedded in JBoss EAP 7.2 is secured by default so you will either need to disable security in the messaging subsystem (e.g. using <security enabled="false"/>
) or add a user to the ApplicationRealm
(e.g. via the bin/add-user.sh
script) and pass the proper credentials when you create your connection.
这篇关于无法将消息发送到嵌入在JBoss EAP 7.2中的远程ActiveMQ Artemis的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!