在如何使用JMS资源以及在activationConfig
注释上使用正确@ActivationConfigProperty
设置@MessageDriven
似乎存在一些不一致。
首先,这是我的资源配置( 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时会出现混淆。以下使用 mappedName 会引发异常:
@MessageDriven(mappedName = "jms/queue/myApp")
public class MessageBean implements MessageListener
警告:RAR8000:类中没有方法setName: org.apache.activemq.command.ActiveMQQueue警告:RAR7097:否 setter方法为类中的属性Name提供 org.apache.activemq.command.ActiveMQQueue信息:访问未访问 参考信息:访问未访问的参考警告:RAR8501: ra [activemq-rar]的端点激活期间出现异常, activationSpecClass [org.apache.activemq.ra.ActiveMQActivationSpec] :javax.resource.ResourceException:未知目标类型:null 严重: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
属性。
ActiveMQ lists the following Activation Spec Properties:
acknowledgeMode (要使用的JMS确认模式。有效值 是:自动确认或Dups-ok-acknowledge)
clientId (要使用的JMS客户端ID(仅限于持久性要求) 主题))
destinationType (目的地类型;队列或主题)
目的地(目的地名称(队列或主题名称))
enableBatch (用于启用事务批处理以增加 性能)
maxMessagesPerBatch (每个事务批处理的邮件数)
maxMessagesPerSessions (这实际上是预取的大小 订阅。 (是的,名字很糟)。)
maxSessions (要使用的最大并发会话数)
messageSelector (要在订阅上使用的JMS消息选择器 执行基于内容的路由过滤消息)
noLocal (仅限主题订阅;指示是否在本地 已发布的消息应该包含在订阅中吗?
密码(JMS连接的密码)
subscriptionDurability (是否为持久(主题)订阅 是必须的。有效值为:Durable或NonDurable)
subscriptionName (持久订阅者的名称。仅用于 持久主题并结合clientID来唯一标识 持久主题订阅)
userName (JMS连接的用户)
useRAManagedTransaction (通常,资源适配器提供 消息到由容器管理的端点。一般, 这个容器喜欢成为想控制它的人 正在传递入站消息的事务。但 有时候,你想要提供一个更简单的容器系统 不控制入境交易。在这些情况下,如果你设置 useRAManagedTransaction为true,资源适配器将提交 如果没有从MessageListener生成异常,则为事务 如果抛出异常则回滚。)
initialRedeliveryDelay (重新开始之前的延迟。此外 可在ResourceAdapter上配置)
maximumRedeliveries (最大重新传送次数或-1次否定 最大值。也可以在ResourceAdapter上配置
redeliveryBackOffMultiplier (指数返回时使用的乘数 关闭已启用。也可以在ResourceAdapter上配置
redeliveryUseExponentialBackOff (启用指数退避。另外 在ResourceAdapter上可配置useJndi,当true为true时,不使用false 目的地为jndi名称)
Java EE7规范lists the following Activation Spec Properties:
acknowledgeMode (此属性用于指定JMS bean管理时消息传递的确认模式 使用事务划分。它的值是Auto_acknowledge或 DUPS_OK_ACKNOWLEDGE。如果未指定此属性,则为JMS 假设是AUTO_ACKNOWLEDGE语义。
messageSelector (此属性用于指定JMS消息 用于确定JMS消息驱动的消息的选择器 豆是接收)
destinationType (此属性用于指定是否显示消息 驱动Bean旨在与队列或主题一起使用。价值 必须是javax.jms.Queue或javax.jms.Topic。)
destinationLookup (此属性用于指定JMS队列或 JMS消息驱动bean从中接收消息的主题。)
connectionFactoryLookup (此属性用于指定JMS 连接工厂,用于连接到JMS提供程序 JMS消息驱动bean从中接收消息。)
subscriptionDurability (如果是消息驱动bean的话 与主题一起使用时,此属性可用于指示是否 应使用持久或非持久订阅。这个的价值 财产必须是耐用的或非耐用的)
subscriptionName (此属性用于指定名称 如果要使用消息驱动的bean,则为持久订阅 有一个主题,并且bean提供商表示持久 应该使用订阅。)
clientId (此属性用于指定JMS客户端标识符 将在连接到JMS的JMS提供程序时使用 消息驱动的bean是接收消息。如果这个属性不是 如果指定,客户端标识符将被取消设置。)
在只有@Inject点和jndi查找的生产者和消费者中使用ActiveMQ资源的正确方法是什么?我想避免使用glassfish-ejb-jar.xml并使用@ActivationConfigProperty
定义队列名称。
答案 0 :(得分:2)
是的,每个应用服务器的工作方式都有所不同。 更重要的是,它们的不同之处不在于您如何配置它 - 这部分很简单,但是当您期望从JMS服务器获得SLA(例如有序消息处理)时的运行时行为 - 即使在出现故障的情况下也是如此。
例如,如果您有业务关键型流程,则只能在消息1之后处理消息2。 并且您的消息1失败,并且您希望重试,但您还配置了200 ms的重新传递延迟。 默认情况下,某些应用程序服务器会认为:消息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等......
在使用ActiveMQ的Wildfly中,您可能希望不使用: JBoss的-ejb3.xml
部署描述符来执行此操作。
因此,通过注释 - 您应该在容器上增加跨越等效元数据的共同点。 在部署描述符中,您使用缺少元数据来丰富配置。
优秀的应用程序服务器将始终执行合并过程,在此过程中,它们将MDB上的元数据与部署描述符上的元数据相结合。 当发生冲突时,它们将接管部署描述符上的配置。
等等。
所以有些人,你真的需要在容器支持的部署描述符中调整pert容器。在您的Java代码中,您应该只保留横切兼容的元数据。
最后,在使用不同JMS服务器实现的不同应用程序服务器上获取消息处理的确切JMS行为......非常棘手。
除非你有一个不关心有序处理的基本scneario,否则在队列中有多个并行运行的MDB,因为在关系之前没有发生...然后让slopy配置工作是微不足道的。 / p>
答案 1 :(得分:0)
似乎所有服务器都有不同的做法。