需要澄清JMS与ActiveMQ bean /资源配置

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

首先,这是我的资源配置( glassfish-resources.xml ,但可以翻译成其他部署描述符)。 这适用于Glassfish( asadmin add-resources glassfish-resources.xml )以及ActiveMQ资源适配器 :

           MyApp JMS Queue     MyApp Connection Factory     

这是我的消息提供者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引发exception:

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

警告:RAR8000:类中不存在方法setName:org.apache.activemq.command.ActiveMQQueue警告:RAR7097:属性中没有setter方法org.apache.activemq.com.ActiveMQQueue类中的名称信息:访问未访问的引用信息:访问未访问的引用警告:RAR8501:ra [activemq-rar],activationSpecClass [org.apache.activemq.ra.ActiveMQActivationSpec]的端点激活期间出现exception:javax.resource.ResourceException:未知目标类型:null严重:MDB00017 :[InvoiceProductionMessageBean]:创建消息驱动的bean容器时出现exception:[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]的端点激活期间出现exception:java.lang.ClassCastException:org.apache.activemq.ra.ActiveMQConnectionFactory无法强制转换为com。 sun.messaging.jms.ra.DirectConnectionFactory严重:MDB00017:[MessageBean]:创建消息驱动的bean容器时出现exception:[java.lang.Exception]严重:java.lang.Exception

与GlassFish ejb-jar.xml中

      MessageBean  activemq-rar     

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

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

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

clientId (要使用的JMS客户端ID(仅适用于持久主题))

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

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

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

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

maxMessagesPerSessions (这实际上是订阅的预取大小。(是的,名字很糟)。)

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

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

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

password (JMS连接的密码)

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

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

userName (JMS连接的用户)

useRAManagedTransaction (通常,资源适配器将消息传递到由容器管理的端点。通常,此容器喜欢是想要控制正在传递入站消息的事务的容器。但有时,您希望传递更简单的容器系统,它不会控制入站事务。在这些情况下,如果将useRAManagedTransaction设置为true,如果没有从MessageListener生成exception,则资源适配器将提交事务,如果抛出exception则返回。)

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

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

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

redeliveryUseExponentialBackOff (要启用指数退避。还可以在ResourceAdapter上配置useJndi,如果为true,则不使用false,使用destination作为jndi名称)

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

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

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

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

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

connectionFactoryLookup (此属性用于指定将用于连接到JMS消息传递接收消息的JMS提供程序的JMS连接工厂。)

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

subscriptionName (如果消息驱动bean旨在与Topic一起使用,则此属性用于指定持久订阅的名称,并且bean提供程序已指示应使用持久订阅。)

clientId (此属性用于指定在连接到JMS消息传递来自JMS消息传递bean的JMS提供程序时将使用的JMS客户端标识符。如果未指定此属性,则将取消设置客户端标识符。 )

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

是的,每个应用服务器的工作方式都有所不同。 更重要的是,它们的不同之处并不是如何配置它 – 这部分很简单,但是当您期望从JMS服务器获得SLA(例如有序消息处理)时,即使在出现故障的情况下,也会出现运行时行为。

例如,如果您有业务关键流程,其中消息2只能在消息1之后处理。并且您的消息1失败,并且您希望重试,但您还配置了200毫秒的重新传递延迟。 一些应用程序服务器,默认情况下会认为:消息1失败,我在200毫秒内重试,跳转到下一条消息…而kabum,业务流程已经死亡,因为您违反了有序消息消耗的预期。

通常,优秀的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等…

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

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

因此,通过注释 – 您应该在容器之间使用交叉切割等效元数据的公分母。 在部署描述符中,您使用缺少元数据来丰富配置。

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

等等。

所以有些人,你真的需要在容器支持的部署描述符中调整pert容器。 在您的Java代码中,您应该只保留横切兼容的元数据。

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

除非你有一个不关心有序处理的基本scneario,你在队列上有多个并行运行的MDB,因为在关系之前没有发生…然后让一个slopy配置工作是微不足道的。

似乎所有服务器都有所不同。