【问题标题】:Need clarification on JMS vs ActiveMQ bean/resource configuration需要澄清 JMS 与 ActiveMQ bean/资源配置
【发布时间】:2015-11-19 15:52:06
【问题描述】:

在如何使用 JMS 资源以及在 @MessageDriven 注释上使用正确的 @ActivationConfigProperty 设置 activationConfig 方面似乎存在一些不一致之处。

首先,这是我的资源配置(glassfish-resources.xml,但可转换为其他部署描述符)。这适用于 Glassfish (asadmin add-resources glassfish-resources.xml) 以及 ActiveMQ Resource Adapter

<?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 时,混乱就开始了。以下使用 ma​​ppedName 会引发异常:

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

警告:RAR8000:类中不存在方法 setName: org.apache.activemq.command.ActiveMQQueue 警告:RAR7097:否 类中的属性名称存在 setter 方法 org.apache.activemq.command.ActiveMQQueue 信息:访问未访问 参考资料:访问未访问的参考资料警告:RAR8501: ra [ activemq-rar ] 的端点激活期间出现异常, activationSpecClass [ org.apache.activemq.ra.ActiveMQActivationSpec ] :javax.resource.ResourceException:未知目标类型:空 严重:MDB00017:[InvoiceProductionMessageBean]:异常 创建消息驱动的 bean 容器:[java.lang.Exception] 严重: java.lang.Exception

我不得不这样定义我的 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 ],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 属性。

ActiveMQlists the following Activation Spec Properties:

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

clientId(要使用的 JMS 客户端 ID(只有持久化时才真正需要) 主题))

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

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

enableBatch(用于启用事务批处理以增加 性能)

ma​​xMessagesPerBatch(每个事务批次的消息数)

ma​​xMessagesPerSessions(这实际上是 订阅。 (是的,名字不好)。)

ma​​xSessions(要使用的最大并发会话数)

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

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

密码(JMS 连接的密码)

subscriptionDurability(是否为持久(主题)订阅 是必须的。有效值为:Durable 或 NonDurable)

subscriptionName(持久订阅者的名称。仅用于 持久主题并结合clientID来唯一标识 持久主题订阅)

userName(JMS 连接的用户)

useRAManagedTransaction(通常,资源适配器提供 消息发送到由容器管理的端点。一般, 这个容器喜欢成为想要控制 正在传递入站消息的事务。但 有时,您希望交付到一个更简单的容器系统,该系统将 不控制入站交易。在这些情况下,如果您设置 useRAManagedTransaction 为 true,资源适配器将提交 如果没有从 MessageListener 生成异常,则事务和 如果抛出异常则回滚。)

initialRedeliveryDelay(重新交付开始前的延迟。还有 可在 ResourceAdapter 上配置)

ma​​ximumRedeliveries(最大重新交付次数或 -1 表示没有 最大。也可在 ResourceAdapter 上配置)

redeliveryBackOffMultiplier(指数返回时使用的乘数 关闭已启用。也可在 ResourceAdapter 上配置)

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

Java EE7 规范lists the following Activation Spec Properties:

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

messageSelector(该属性用于指定JMS消息 用于确定 JMS 消息驱动的消息的选择器 bean是接收)

destinationType(该属性用于指定是否发送消息 驱动 bean 旨在与队列或主题一起使用。价值 必须是 javax.jms.Queue 或 javax.jms.Topic。)

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

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

subscriptionDurability(如果消息驱动 bean 旨在 与主题一起使用,此属性可用于指示是否 应使用持久或非持久订阅。这个的价值 属性必须是 Durable 或 NonDurable)

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

clientId(此属性用于指定 JMS 客户端标识符 将在连接到 JMS 提供程序时使用 消息驱动bean就是接收消息。如果这个属性不是 指定,则客户端标识符将保持未设置。)

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

【问题讨论】:

    标签: java glassfish jms activemq ejb-3.1


    【解决方案1】:

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

    例如,如果您有一个业务关键流程,其中消息 2 只能在消息 1 之后处理。 而你的消息 1 失败了,你想被重试,但你也配置了 200 毫秒的重新传递延迟。 一些应用服务器,默认会认为:message 1 failed, I retry it in 200 ms, jumpt to next message ... 而且kabum,业务流程已死,因为您对有序消息消费的期望刚刚被违反。

    通常,良好的 JMS 服务器能够以您可以满足所需 SLA 的方式对其进行配置......但这很棘手。

    通常,您应该通过注释在 MDB 上进行配置,任何在多个应用程序服务器上交叉工作的属性。 通常,JNDI 命名可以工作 - 但它很棘手,因为 JNDI 高度依赖于容器。 属性如: - 激活属性: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 行为......非常棘手。

    除非您有不关心有序处理的基本场景,否则您有多个 MDB 在队列上并行运行,因为在关系之前不会发生...然后让一个草率的配置工作是微不足道的。

    【讨论】:

      【解决方案2】:

      似乎所有服务器的做法都略有不同。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-10-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-20
        • 2011-11-09
        • 2012-07-18
        • 1970-01-01
        相关资源
        最近更新 更多