当前位置: 首页 > 知识库问答 >
问题:

需要说明JMS与ActiveMQ bean/资源配置

郎献
2023-03-14

在如何使用JMS资源以及在@messagedriven注释上使用适当的@activationconfig设置activationconfig似乎存在一些不一致。

首先,这里是我的资源配置(glassfish-resources.xml,但可转换为其他部署描述符)。这将与ActiveMQ资源适配器一起应用于Glassfish(asadmin add-resources.xml):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE resources PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Resource Definitions//EN" "http://glassfish.org/dtds/glassfish-resources_1_5.dtd">
<resources>

    <resource-adapter-config name="activemq-rar" 
                             thread-pool-ids="thread-pool-1" 
                             resource-adapter-name="activemq-rar">
        <property name="ServerUrl" value="tcp://localhost:61616"/>
        <property name="UserName" value="admin"/>
        <property name="Password" value="admin"/>
        <property name="UseInboundSession" value="false"/>
    </resource-adapter-config>
    <admin-object-resource enabled="true" 
                           jndi-name="jms/queue/myApp" 
                           object-type="user" 
                           res-adapter="activemq-rar" 
                           res-type="javax.jms.Queue">
        <description>MyApp JMS Queue</description>
        <property name="Name" value="myAppAMQ"/>
        <property name="PhysicalName" value="myAppAMQ"/>     
    </admin-object-resource>
    <connector-resource enabled="true" 
                        jndi-name="jms/factory/myApp" 
                        object-type="user" 
                        pool-name="jms/factoryPool/myApp">
        <description>MyApp Connection Factory</description>
        <property name="Name" value="myAppFactory"/>
    </connector-resource>
    <connector-connection-pool associate-with-thread="false" 
                               connection-creation-retry-attempts="0" 
                               connection-creation-retry-interval-in-seconds="10" 
                               connection-definition-name="javax.jms.QueueConnectionFactory" 
                               connection-leak-reclaim="false" 
                               connection-leak-timeout-in-seconds="0" 
                               fail-all-connections="false" 
                               idle-timeout-in-seconds="300" 
                               is-connection-validation-required="false" 
                               lazy-connection-association="false" 
                               lazy-connection-enlistment="false" 
                               match-connections="true" 
                               max-connection-usage-count="0" 
                               max-pool-size="32" 
                               max-wait-time-in-millis="60000" 
                               name="jms/factoryPool/myApp" 
                               ping="false" 
                               pool-resize-quantity="2" 
                               pooling="true" 
                               resource-adapter-name="activemq-rar" 
                               steady-pool-size="8" 
                               validate-atmost-once-period-in-seconds="0"/>
</resources>

这是我的消息提供者bean。您将注意到,找到了JNDI名称,并且使用了ActiveMQ资源,消息被发送到正确的队列:

@Stateless
@LocalBean
public class ServicesHandlerBean {

    @Resource(mappedName = "jms/queue/myApp")
    private Queue queue;
    @Resource(mappedName = "jms/factory/myApp")
    private ConnectionFactory factory;

    public void sendJMSMessage(MessageConfig messageData) throws JMSException {
        Connection connection = null;
        Session session = null;
        try {
            connection = factory.createConnection();
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            MessageProducer messageProducer = session.createProducer(queue);
            messageProducer.send(createJMSMessage(session, messageData));
        } finally {
            if (session != null) {
                try {
                    session.close();
                } catch (JMSException e) {
                    Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Cannot close session", e);
                }
            }
            if (connection != null) {
                connection.close();
            }
        }
    }
}

混乱开始于定义@MessageDriven bean。使用mappedName的以下操作引发异常:

@MessageDriven(mappedName = "jms/queue/myApp")
public class MessageBean implements MessageListener

警告:RAR8000:类中不存在方法setName:org.apache.activeMQ.command.activeMQQueue警告:RAR7097:类中不存在属性名称的setter方法:访问未访问的引用信息:访问未访问的引用警告:RAR8501:ra[activemq-rar],activationSpecClass[org.apache.activeMQ.ra.activeMQactivationspec]:javax.resource.resourceException:未知目标类型:null严重:MDB00017:[InvoiceProductionMessageBean]:创建消息驱动bean容器时的异常

我不得不这样定义我的MDB:

@MessageDriven(
        activationConfig = {
            @ActivationConfigProperty(propertyName = "connectionFactoryLookup", propertyValue = "jms/factory/myApp"),
            @ActivationConfigProperty(propertyName = "destination", propertyValue = "myAppAMQ"),
            @ActivationConfigProperty(propertyName = "messageSelector", propertyValue = " JMSType = 'TypeA' "),
            @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")
        }
)
public class MessageBean implements MessageListener

并且我需要提供一个glassfish-ejb-jar.xml通知容器使用ActiveMQ资源,否则我将得到一个java.lang.ClassCastException:

警告:RAR8501:激活ra[jmsra]的endpoint期间发生异常,activationSpecClass[com.sun.messaging.jms.ra.ActivationSpec]:java.lang.ClassCastException:org.apache.activemq.ra.ActiveMQConnectionFactory无法强制转换为com.sun.messaging.jms.ra.DirectConnectionFactory严重:MDB00017:[MessageBean]:创建消息驱动bean容器时发生异常:[java.lang.Exception]严重:java.lang.Exception

glassfish-ejb-jar.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE glassfish-ejb-jar PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 EJB 3.1//EN" "http://glassfish.org/dtds/glassfish-ejb-jar_3_1-1.dtd">
<glassfish-ejb-jar>
    <enterprise-beans>
        <ejb>
            <ejb-name>MessageBean</ejb-name>
            <mdb-resource-adapter>
                <resource-adapter-mid>activemq-rar</resource-adapter-mid>
            </mdb-resource-adapter>
        </ejb>
    </enterprise-beans>
</glassfish-ejb-jar>

因此,在生产者如何使用资源(JNDI)和使用者如何使用资源(XML+@ActivationConfigProperty)之间似乎存在一些不一致。此外,EE7 ActivationConfigProperty属性似乎不起作用。例如,使用destinationLookup不会查找目标,我被迫使用ActiveMQ的destination属性。

ActiveMQ列出以下激活规范属性:

acknowledgeMode(要使用的JMS确认模式。有效值为:Auto-acknowledge或Dups-ok-acknowledge)

clientId(要使用的JMS客户端ID(仅在持久主题中真正需要))

destinationType(目标的类型;队列或主题)

目标(目标名称(队列或主题名称))

enableBatch(用于启用事务批处理以提高性能)

maxMessagesPerBatch(每个事务批的消息数)

maxMessagesPerSessions(这实际上是订阅的预取大小。(是的,命名错误)。)

maxSessions(要使用的最大并发会话数)

messageSelector(用于订阅的JMS消息选择器,用于执行基于内容的路由筛选消息)

noLocal(仅主题订阅必需;指示本地发布的消息是否应包含在订阅中)

密码(JMS连接的密码)

subscriptionDurability(无论是否需要持久(主题)订阅。有效值为:持久或非持久)

subscriptionName(持久订阅服务器的名称。仅用于持久主题,并与clientID组合以唯一标识持久主题订阅)

userName(JMS连接的用户)

useRAManagedTransaction(通常,资源适配器将消息传递到由容器管理的终结点。通常,该容器希望控制正在传递入站消息的事务。但有时,您希望传递到不控制入站事务的更简单的容器系统。在这些情况下,如果将useRAManagedTransaction设置为true,则如果MessageListener未生成异常,则资源适配器将提交事务,如果引发异常,则将回滚。)

initialRedeliveryDelay(重新传递开始前的延迟。也可在ResourceAdapter上配置)

maximumRedeliveries(重新传递的最大数目,或-1表示没有最大值。也可在ResourceAdapter上配置)

redeliveryBackOffMultiplier(如果启用了指数回退,则使用的乘法器。也可在ResourceAdapter上配置)

redeliveryUseExponentialBackOff(启用指数退避。也可在ResourceAdapter上配置useJndi no false当true时,使用destination作为jndi名称)

Java EE7规范列出了以下激活规范属性:

AcknowdgEmode(此属性用于在使用bean管理的事务划分时为消息传递指定JMS确认模式。其值为Auto_acknowledge或dups_ok_acknowledge。如果未指定此属性,则假定为JMS Auto_acknowledge语义。

messageSelector(此属性用于指定JMS消息选择器,用于确定JMS消息驱动bean要接收哪些消息)

destinationType(此属性用于指定消息驱动bean是用于队列还是用于主题。值必须是javax.jms.queue或javax.jms.topic。)

destinationLookup(该属性用于指定JMS消息驱动bean接收消息的JMS队列或主题。)

connectionFactoryLookup(该属性用于指定将用于连接到JMS提供程序的JMS连接工厂,JMS消息驱动bean将从该JMS提供程序接收消息。)

subscriptionDurability(如果消息驱动bean打算与主题一起使用,则该属性可用于指示应该使用持久订阅还是非持久订阅。该属性的值必须是持久的或非持久的)

subscriptionName(如果消息驱动的bean打算与主题一起使用,并且bean提供者已经指示应该使用持久订阅,则该属性用于指定持久订阅的名称。)

clientId(此属性用于指定JMS客户端标识符,当连接到JMS提供程序时,JMS消息驱动bean将从该提供程序接收消息。如果未指定此属性,则客户端标识符将未设置。)

只有@inject点和jndi查找,在生产者和消费者中使用ActiveMQ资源的正确方法是什么?我希望避免使用glassfish-ejb-jar.xml并使用@ActivationConfigProperty定义队列名称。

共有2个答案

雍俊远
2023-03-14

似乎所有服务器的操作都有点不同。

宰父志新
2023-03-14

是的,每个应用服务器做的事情有点不同。更重要的是,它们的做法不同,不在于如何配置它(这部分很简单),而是在于当您期望从JMS服务器获得SLA(如有序消息处理)时的运行时行为(即使在失败的情况下也是如此)。

例如,如果您有一个业务关键流程,其中只能在消息1之后处理消息2。并且您的邮件%1失败,您希望重试,但您还配置了200 ms的重新传递延迟。某些应用服务器默认情况下会认为:消息1失败,我在200毫秒内重试,跳转到下一条消息...

正常情况下,好的JMS服务器提供了这样的配置能力,使您能够满足所需的SLA...但这是很棘手的。

通常,您应该通过批注在MDB上进行配置,批注是在多个应用程序服务器上交叉工作的任何属性。通常,JNDI命名是可以工作的,但它很棘手,因为JNDI高度依赖于容器。属性,如:-Activation propertu:destinationType=javax.jms.topic

这是相当相当标准的,所以你可以把它通过注释。

但当您遇到棘手的方面时,例如指定连接工厂以连接到目标时。或者您应该允许JMS服务器一次批量读取N条消息,或者您希望强制它一次读取一条消息,等等。这高度依赖于您的容器,您将希望配置这一点,而不是通过ejb部署描述符进行注释。

例如,在weblogic中,您需要使用:weblogic-ejb-jar.xml来微调诸如JNDI名称之类的东西,以访问队列、max-beans-in-free-pool等。

在使用ActiveMQ的Wildfly中,您不希望使用:jboss-ejb3.xml

部署描述符来执行此操作。

因此,通过注解--您应该在容器中实现跨切等价元数据的共同分母。在部署描述符中,使用缺少的元数据丰富配置。

好的应用程序服务器总是在执行合并过程,它们将MDB上的元数据与部署描述符上的元数据结合起来。当发生冲突时,它们接管部署描述符上的配置。

等等。

因此,在某些情况下,您确实需要在容器支持的部署描述符中调整pert容器。在您的Java代码中,您应该只保留交叉兼容的元数据。

最后,在使用不同JMS服务器实现的不同应用程序服务器上获取消息处理的确切JMS行为是相当棘手的。

除非您具有不关心有序处理的基本scneario,否则您将有多个MDB并行运行在一个队列上,因为没有发生之前的关系...那么让一个草率的配置工作就很简单了。

 类似资料:
  • 问题内容: 在如何使用JMS资源以及在注释上使用适当的设置方面似乎存在一些不一致之处。 首先,这是我的资源配置( glassfish-resources.xml ,但可以翻译为其他部署描述符)。这与ActiveMQ资源适配器一起应用于Glassfish(): 这是我的消息提供程序bean。您会注意到找到了JNDI名称,并且使用了ActiveMQ资源而没有错误,该消息已发送到适当的队列: 当定义一个

  • 问题内容: 我的代码是: 输出: 请向我解释一下,由于该方法已被覆盖,为什么这个问题的输出是“ b 3”而不是“ b 13”? 问题答案: 您无法在Java中覆盖变量,因此实际上您有两个变量-一in 和in in 。在另一方面的方法是多态的,因而它修改(被调用时,尽管静态类型的存在)。 但最终你访问这个参考使用已知类型的编译过程中解决了,这是。因此从未被感动。 Java中的BTW非最终变量 绝对

  • 这是针对Gitea配置文件的说明,你可以了解Gitea的强大配置。需要说明的是,你的所有改变请修改 custom/conf/app.ini 文件而不是源文件。所有默认值可以通过 app.example.ini 查看到。如果你发现 %(X)s 这样的内容,请查看 ini 这里的说明。标注了 ? 的配置项表明除非你真的理解这个配置项的意义,否则最好使用默认值。 Overall (DEFAULT) AP

  • 通过配置以下各项参数,可以改变播放器的界面,开启更多的回调接口,还可以使用其他的功能,如自定义全屏、字幕功能。配置播放器的方法可参照下方示例,配置项如下所示: 配置项 功能描述 control_enable 是否显示控制条 0, 不显示;1, 显示;默认值为1 progressbar_enable 是否可操作进度条 0, 不可操作;1, 可操作;默认值为1 loadingpic_enable 是否

  • 我需要动态设置通知图像图标,它的名字动态传递给我的类。为此,我需要设置builder.setSmallIcon(intres_id)。我谷歌了一下,但是人们已经使用了setDrawableImage()的例子,我已经看到了这篇文章,并相应地在我的代码中实现。 当然,这会显示错误,因为setSmallIcon()需要将整数传递给它。con是传递给我的构造函数的上下文。我已经看到如何在android中

  • 如果我想在任意两个外部电子邮件地址(比如gmail)之间发送电子邮件,请使用Javamail API通过我的应用程序- 配置javamail属性以在任意两个外部电子邮件地址之间发送电子邮件的正确方法是什么? 发送邮件的示例代码如下所示: