Error: AMQ154003: Unable to connect to JMS ActiveMQ using Wildfly

Error: AMQ154003: Unable to connect to JMS ActiveMQ using Wildfly

我正在尝试使用 IntelliJ 在 WildFly 19 中创建一个简单的 JMS ActiveMQ 连接。我已遵循设置指南,但遇到连接错误。

我 运行 Wildfly 作为本地服务器,处于独立模式。我更新了 IntelliJ 中的 Startup Script 环境变量,指向 standalone-full.xml(显然我需要使用 standalone-full.xml,才能使用 JMS?)

/Users/../IdeaProjects/appservers/wildfly-19.1.0.Final/bin/standalone.sh
JAVA_OPTS environment variable -Djboss.server.default.config=standalone-full.xml

我已经更新了 XML 文件以在我的代码中添加我正在连接的 JMS 队列:

<jms-queue name="HsportsQueue" entries="java:/jms/queue/HsportsQueue"/>

EAR 正在部署,JSF 正在呈现,但我收到 JMS 错误,它在堆栈跟踪中无限循环。我附上了 standalone-full.xml、堆栈跟踪和 java 代码。

如有任何帮助,我们将不胜感激。

standalone-full.xml(由于字符限制,已编辑):

<?xml version='1.0' encoding='UTF-8'?>

<server xmlns="urn:jboss:domain:12.0">
    <extensions>
        <extension module="org.jboss.as.clustering.infinispan"/>
        <extension module="org.jboss.as.connector"/>
        <extension module="org.jboss.as.deployment-scanner"/>
        <extension module="org.jboss.as.ee"/>
        <extension module="org.jboss.as.ejb3"/>
        <extension module="org.jboss.as.jaxrs"/>
        <extension module="org.jboss.as.jdr"/>
        <extension module="org.jboss.as.jmx"/>
        <extension module="org.jboss.as.jpa"/>
        <extension module="org.jboss.as.jsf"/>
        <extension module="org.jboss.as.jsr77"/>
        <extension module="org.jboss.as.logging"/>
        <extension module="org.jboss.as.mail"/>
        <extension module="org.jboss.as.naming"/>
        <extension module="org.jboss.as.pojo"/>
        <extension module="org.jboss.as.remoting"/>
        <extension module="org.jboss.as.sar"/>
        <extension module="org.jboss.as.security"/>
        <extension module="org.jboss.as.transactions"/>
        <extension module="org.jboss.as.webservices"/>
        <extension module="org.jboss.as.weld"/>
        <extension module="org.wildfly.extension.batch.jberet"/>
        <extension module="org.wildfly.extension.bean-validation"/>
        <extension module="org.wildfly.extension.clustering.web"/>
        <extension module="org.wildfly.extension.core-management"/>
        <extension module="org.wildfly.extension.discovery"/>
        <extension module="org.wildfly.extension.ee-security"/>
        <extension module="org.wildfly.extension.elytron"/>
        <extension module="org.wildfly.extension.io"/>
        <extension module="org.wildfly.extension.messaging-activemq"/>
        <extension module="org.wildfly.extension.microprofile.config-smallrye"/>
        <extension module="org.wildfly.extension.microprofile.health-smallrye"/>
        <extension module="org.wildfly.extension.microprofile.jwt-smallrye"/>
        <extension module="org.wildfly.extension.microprofile.metrics-smallrye"/>
        <extension module="org.wildfly.extension.microprofile.opentracing-smallrye"/>
        <extension module="org.wildfly.extension.request-controller"/>
        <extension module="org.wildfly.extension.security.manager"/>
        <extension module="org.wildfly.extension.undertow"/>
        <extension module="org.wildfly.iiop-openjdk"/>
    </extensions>

    <subsystem xmlns="urn:jboss:domain:ejb3:6.0">
        <session-bean>
            <stateless>
                <bean-instance-pool-ref pool-name="slsb-strict-max-pool"/>
            </stateless>
            <stateful default-access-timeout="5000" cache-ref="simple" passivation-disabled-cache-ref="simple"/>
            <singleton default-access-timeout="5000"/>
        </session-bean>
        <mdb>
            <resource-adapter-ref resource-adapter-name="${ejb.resource-adapter-name:activemq-ra.rar}"/>
            <bean-instance-pool-ref pool-name="mdb-strict-max-pool"/>
        </mdb>
        <pools>
            <bean-instance-pools>
                <strict-max-pool name="mdb-strict-max-pool" derive-size="from-cpu-count" instance-acquisition-timeout="5" instance-acquisition-timeout-unit="MINUTES"/>
                <strict-max-pool name="slsb-strict-max-pool" derive-size="from-worker-pools" instance-acquisition-timeout="5" instance-acquisition-timeout-unit="MINUTES"/>
            </bean-instance-pools>
        </pools>
        <caches>
            <cache name="simple"/>
            <cache name="distributable" passivation-store-ref="infinispan" aliases="passivating clustered"/>
        </caches>
        <passivation-stores>
            <passivation-store name="infinispan" cache-container="ejb" max-size="10000"/>
        </passivation-stores>
        <async thread-pool-name="default"/>
        <timer-service thread-pool-name="default" default-data-store="default-file-store">
            <data-stores>
                <file-data-store name="default-file-store" path="timer-service-data" relative-to="jboss.server.data.dir"/>
            </data-stores>
        </timer-service>
        <remote connector-ref="http-remoting-connector" thread-pool-name="default">
            <channel-creation-options>
                <option name="MAX_OUTBOUND_MESSAGES" value="1234" type="remoting"/>
            </channel-creation-options>
        </remote>
        <thread-pools>
            <thread-pool name="default">
                <max-threads count="10"/>
                <keepalive-time time="60" unit="seconds"/>
            </thread-pool>
        </thread-pools>
        <iiop enable-by-default="false" use-qualified-name="false"/>
        <default-security-domain value="other"/>
        <default-missing-method-permissions-deny-access value="true"/>
        <statistics enabled="${wildfly.ejb3.statistics-enabled:${wildfly.statistics-enabled:false}}"/>
        <log-system-exceptions value="true"/>
    </subsystem>

    <subsystem xmlns="urn:jboss:domain:messaging-activemq:9.0">
        <server name="default">
            <statistics enabled="${wildfly.messaging-activemq.statistics-enabled:${wildfly.statistics-enabled:false}}"/>
            <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="ExpiryQueue" entries="java:/jms/queue/ExpiryQueue"/>
            <jms-queue name="DLQ" entries="java:/jms/queue/DLQ"/>
            <jms-queue name="HsportsQueue" entries="java:/jms/queue/HsportsQueue"/>
            <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>
    ...
</server>

错误堆栈跟踪

10:30:55,530 ERROR [org.apache.activemq.artemis.ra] (default-threads - 1) AMQ154003: Unable to reconnect org.apache.activemq.artemis.ra.inflow.ActiveMQActivationSpec(ra=org.wildfly.extension.messaging.activemq.ActiveMQResourceAdapter@798f9ea7 destination=javax.jms.Queue destinationType=null ack=Auto-acknowledge durable=false clientID=null user=null maxSession=15): javax.naming.NameNotFoundException: javax.jms.Queue -- service jboss.naming.context.java."javax.jms.Queue"
    at org.jboss.as.naming.ServiceBasedNamingStore.lookup(ServiceBasedNamingStore.java:106)
    at org.jboss.as.naming.NamingContext.lookup(NamingContext.java:207)
    at org.jboss.as.naming.InitialContext$DefaultInitialContext.lookup(InitialContext.java:237)
    at org.jboss.as.naming.NamingContext.lookup(NamingContext.java:193)
    at org.jboss.as.naming.NamingContext.lookup(NamingContext.java:189)
    at javax.naming.InitialContext.lookup(InitialContext.java:417)
    at javax.naming.InitialContext.lookup(InitialContext.java:417)
    at org.apache.activemq.artemis.ra.ActiveMQRaUtils.lookup(ActiveMQRaUtils.java:164)
    at org.apache.activemq.artemis.ra.inflow.ActiveMQActivation.setupDestination(ActiveMQActivation.java:578)
    at org.apache.activemq.artemis.ra.inflow.ActiveMQActivation.setup(ActiveMQActivation.java:305)
    at org.apache.activemq.artemis.ra.inflow.ActiveMQActivation.reconnect(ActiveMQActivation.java:693)
    at org.apache.activemq.artemis.ra.inflow.ActiveMQActivation$SetupActivation.run(ActiveMQActivation.java:733)
    at org.wildfly.extension.messaging.activemq.ActiveMQResourceAdapter$WorkWrapper.run(ActiveMQResourceAdapter.java:161)
    at org.jboss.jca.core.workmanager.WorkWrapper.runWork(WorkWrapper.java:445)
    at org.jboss.as.connector.services.workmanager.WildflyWorkWrapper.runWork(WildflyWorkWrapper.java:69)
    at org.jboss.jca.core.workmanager.WorkWrapper.run(WorkWrapper.java:223)
    at org.jboss.threads.SimpleDirectExecutor.execute(SimpleDirectExecutor.java:29)
    at org.jboss.threads.QueueExecutor.runTask(QueueExecutor.java:789)
    at org.jboss.threads.QueueExecutor.access0(QueueExecutor.java:44)
    at org.jboss.threads.QueueExecutor$Worker.run(QueueExecutor.java:809)
    at java.lang.Thread.run(Thread.java:748)
    at org.jboss.threads.JBossThread.run(JBossThread.java:485)

JMS 消费者class:

package ejb_javacode;

@MessageDriven(
        activationConfig = {
                @ActivationConfigProperty(propertyName = "destination", propertyValue = "/jms/queue/HsportsQueue"),
                @ActivationConfigProperty(propertyName = "destination", propertyValue = "javax.jms.Queue")
        },
        mappedName = "/jms/queue/HsportsQueue")

public class JmsConsumerBean implements javax.jms.MessageListener {

    public JmsConsumerBean() {
    }

    // defines what the consumer does, when msg is received from jms queue

    @Override
    public void onMessage(Message message) {

        System.out.println("From JMS Consumer message-driven bean");
        try {
            System.out.println(message.getBody(String.class));
        } catch (JMSException e) {
            e.printStackTrace();
        }
    }
}

JMS 生产者class:

package jaxrs_javacode;

@ApplicationScoped
public class JmsService {

    // injects JMS queue we want to send the message to
    @Resource(mappedName = "java:/jms/queue/HsportsQueue")  // JNDI name
    private Queue hsportsQueue;

    @Inject
    @JMSConnectionFactory("java:/ConnectionFactory")
    private JMSContext context;

    // code that sends the message to the consumer
    public void send(String message) {

        try {
            TextMessage textMessage = context.createTextMessage(message);   
            context.createProducer().send(hsportsQueue, textMessage);       
            System.out.println("Message sent to JMS queue");                

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

JAX-RS 资源端点:

package jaxrs_javacode;


// resource defines the various http operations required
@RequestScoped
@Path("/inventoryitems")                // appends URI app path
@Produces("application/json")           // receives and provides json
@Consumes("application/json")
public class InventoryItemEndpoint {

    // adds JPS persistence
    // methods updated to use em & jpa data layer
    @PersistenceContext
    private EntityManager entityManager;

    // injects JMS service into REST endpoint
    @Inject
    private JmsService jmsService;

    @Transactional
    @POST   // post request; creates new inventory item and gets response back
    public Response create(final InventoryItem inventoryItem) {

        entityManager.persist(inventoryItem); // uses em persist method
        jmsService.send(inventoryItem.getName()); // sends inventory item name as JMS text msg
        return Response.created(UriBuilder.fromResource(InventoryItemEndpoint.class)
                .path(String.valueOf(inventoryItem.getInventoryItemId())).build()).build();
    }

    @GET    // get request; gets inventory item by id
    @Path("/{id:[0-9][0-9]*}")  // method level @Path annotation, appends URI with id value
    public Response findById(@PathParam("id") final Long id) {

        // now using em find method
        InventoryItem inventoryItem = entityManager.find(InventoryItem.class, id);

        if (inventoryItem == null) {
            return Response.status(Response.Status.NOT_FOUND).build();
        }

        inventoryItem.setQuantity(ThreadLocalRandom.current().nextLong(1,100));
        return Response.ok(inventoryItem).build();
    }

    // new async method; async methods are void
    // onward processing done through resume() method call

    @GET
    @Path("/catalog/{catalogItemId}")
    public void asyncFindByCatalogId(@NotNull @PathParam("catalogItemId") Long catalogItemId,
                                     @Suspended AsyncResponse ar) {

        // creates new thread
        // sleeps for 5 seconds
        new Thread(() -> {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // tells AsyncResponse to resume, once thread.sleep completes
            // resumes with call to findByCatalogId
            ar.resume(findByCatalogId(catalogItemId));
        }).start();
    }

    // used by getQuantity method on remote inventory service
    // takes catalogItemId as param
    // @GET
    // @Path("/catalog/{catalogItemId}") // appends path // updates from @QueryParam to @PathParam
    // Mapping annotations removed; is now called from asyncMethod above
    public InventoryItem findByCatalogId(@NotNull @PathParam("catalogItemId") Long catalogItemId) {

        TypedQuery<InventoryItem> query = this.entityManager
                .createQuery("select i from InventoryItem i where i.catalogItemId = :catalogItemId", InventoryItem.class)
                .setParameter("catalogItemId", catalogItemId);

        InventoryItem item = query.getSingleResult();
        item.setQuantity(ThreadLocalRandom.current().nextLong(1,100));

        return item;
    }

    @GET    // gets all inventory items
    public List<InventoryItem> listAll(@QueryParam("start") final Integer startPosition,
                                       @QueryParam("max") final Integer maxResult) {

        TypedQuery<InventoryItem> query = entityManager.createQuery("select i from InventoryItem i",
                InventoryItem.class); // now uses em createQuery method

        final List<InventoryItem> inventoryItems = query.getResultList();
        return inventoryItems;
    }

    @Transactional
    @PUT    // updates existing inventory item
    @Path("/{id:[0-9][0-9]*}")
    public Response update(@PathParam("id") Long id, final InventoryItem inventoryItem) {
        entityManager.merge(inventoryItem); // now uses em.merge method
        return Response.noContent().build();
    }

    @Transactional
    @DELETE // deletes an item from inventory
    @Path("/{id:[0-9][0-9]*}")
    public Response deleteById(@PathParam("id") final Long id) {
        entityManager.remove(entityManager.find(InventoryItem.class, id)); // now uses em.remove method
        return Response.noContent().build();
    }
}

我认为问题出在您的激活配置上。您已经定义了 destination 属性 两次:

@MessageDriven(activationConfig = {
                   @ActivationConfigProperty(propertyName = "destination", propertyValue = "/jms/queue/HsportsQueue"),
                   @ActivationConfigProperty(propertyName = "destination", propertyValue = "javax.jms.Queue")
               },
               mappedName = "/jms/queue/HsportsQueue")

因此 JCA 资源适配器试图在 JNDI 中查找 "javax.jms.Queue" 因此出现错误:

javax.naming.NameNotFoundException: javax.jms.Queue -- service jboss.naming.context.java."javax.jms.Queue"

值为javax.jms.Queue的属性应该使用名称destinationType:


@MessageDriven(activationConfig = {
                   @ActivationConfigProperty(propertyName = "destination", propertyValue = "/jms/queue/HsportsQueue"),
                   @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")
               },
               mappedName = "/jms/queue/HsportsQueue")