您好我正在使用ActiveMQ学习Spring JMS。 在我的示例场景中,Producer应用程序在队列中发送大约50条消息,当我启动Consumer应用程序时,它开始使用这些消息。
现在我希望多个消费者线程使用来自队列的消息。 我正在使用 JMS侦听器容器。当我用Google搜索时,我发现有一个并发属性。
根据Spring JMS doc并发属性指定
为每个侦听器启动的并发会话/使用者数。可以是表示最大数字的简单数字(例如“5”)或表示较低数字和上限的范围(例如“3-5”)。请注意,指定的最小值只是一个提示,可能在运行时被忽略。默认值为1;在主题监听器或队列排序很重要的情况下,将并发性限制为1;考虑将其提升为一般队列。
但在我的配置中,我将此属性设置为5,但似乎无法启动5个并发侦听器。
侦听器的配置:
消费者的applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jms="http://www.springframework.org/schema/jms"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms-3.0.xsd">
<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory" p:brokerURL="tcp://localhost:61616" />
<bean id="listener" class="com.jms.example.MyMessageListener"></bean>
<jms:listener-container container-type="default" concurrency="5"
connection-factory="connectionFactory">
<jms:listener destination="MyQueue" ref="listener"
method="onMessage"></jms:listener>
</jms:listener-container>
</beans>
如果我使用bean DefaultMessageListenerContainer 而不是 jms:listener-container 并使用属性:
<bean id="msgListenerContainer"
class="org.springframework.jms.listener.DefaultMessageListenerContainer"
p:connectionFactory-ref="connectionFactory"
p:destination-ref="destination"
p:messageListener-ref="listener"
p:concurrentConsumers="10"
p:maxConcurrentConsumers="50" />
然后在ActiveMQ控制台中我可以看到10个消费者,但实际上它同时启动了3个消费者,有时甚至是6个消费者或者只有1个消费者。
修改
消费者代码:
public class MyMessageListener implements MessageListener{
public void onMessage(Message m) {
TextMessage message=(TextMessage)m;
try{
System.out.println("Start = " + message.getText());
Thread.sleep(5000);
System.out.println("End = " + message.getText());
}catch (Exception e) {e.printStackTrace(); }
}
}
我在控制台上打印消费消息,其输出在下面的场景中解释:
观察:
我发现了一些奇怪的行为。 我的制作人和消费者是两个独立的应用。
情景 - 1:
这里的问题是它不会加载所有10个消费者。有时加载3或1。
Start = hello jms 1 // consumer 1 started
Start = hello jms 2 // consumer 2 started
Start = hello jms 3 // consumer 3 started
End = hello jms 1 // consumer 1 ended
Start = hello jms 4 // consumer 4 started and hence always 3 consumers and not 10
End = hello jms 2
Start = hello jms 5
End = hello jms 3
Start = hello jms 6
情景 - 2:
所以它确实按预期正确加载了所有5个消费者。所以输出是:
Start = hello jms 1 // consumer 1 started
Start = hello jms 2 // consumer 2 started
Start = hello jms 3 // consumer 3 started
Start = hello jms 4 // consumer 4 started
Start = hello jms 5 // consumer 5 started
Start = hello jms 6 // consumer 6 started
Start = hello jms 7 // consumer 7 started
Start = hello jms 8 // consumer 8 started
Start = hello jms 9 // consumer 9 started
Start = hello jms 10 // consumer 10 started. Hence all them started at same time as expected.
End = hello jms 1
Start = hello jms 11
End = hello jms 2
Start = hello jms 12
End = hello jms 3
Start = hello jms 13
为什么会这样。它真的在吃我的大脑。 我不想让消费者永远奔跑。我想保持两个分离。
请帮忙。
答案 0 :(得分:0)
Strelok向我指出了预取消息的方法。创建prefetchPolicy
bean,queuePrefetch
属性设置为1。
在connectionFactory中设置了哪个引用。
我在配置上做了一些更改,如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jms="http://www.springframework.org/schema/jms"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms-3.0.xsd">
<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory" p:brokerURL="tcp://localhost:61616"
p:prefetchPolicy-ref="prefetchPolicy" />
<bean id="prefetchPolicy" class="org.apache.activemq.ActiveMQPrefetchPolicy"
p:queuePrefetch="1" />
<bean id="listener" class="com.javatpoint.MyMessageListener"></bean>
<jms:listener-container concurrency="10-15" connection-factory="connectionFactory">
<jms:listener destination="javatpointQueue" ref="listener"
method="onMessage"></jms:listener>
</jms:listener-container>
<!-- The JMS destination -->
<bean id="destination" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="javatpointQueue" />
</bean>
</beans>
答案 1 :(得分:0)
JMS可以在并发模式下工作。下面我分享了示例代码段 concurrentConsumers = 100值
<bean id="listenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="concurrentConsumers">
<value>100</value>
</property>
<property name="connectionFactory" ref="connectionFactory" />
<property name="destination" ref="queue" />
<property name="messageListener" ref="messageListener" />
<property name="sessionTransacted" value="false" />
<property name="sessionAcknowledgeMode" value="1" />
</bean>
答案 2 :(得分:0)
刚刚在spring-boot 1.5.9应用程序中遇到了这个问题。
正如@Strelok和@mahendra kawde所指出的,问题是由prefetchPolicy参数引起的。默认值为1000。
对于具有高消息量的高性能,建议使用较大的预取值。但是,对于较低的消息量,每个消息需要很长时间才能处理,预取应设置为1.这可确保消费者一次只处理一条消息。但是,将预取限制指定为零将导致使用者一次一个地轮询消息,而不是将消息推送到消费者。
查看http://activemq.apache.org/what-is-the-prefetch-limit-for.html
可以更改prefetchPolicy参数,如下所示:
在application.properties
档案(working example)
spring.activemq.broker-url=tcp://localhost:61616?jms.prefetchPolicy.queuePrefetch=1
在DefaultMessageListenerContainer中修改destinationName参数(working example)
<bean id="cons-even" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="destinationName" value="queue-name?consumer.prefetchSize=1"/>
...
</bean>
在ConnectionFactory bean(working example)中:
@Bean
public ConnectionFactory jmsConnectionFactory() {
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(brokerUrl);
ActiveMQPrefetchPolicy policy = new ActiveMQPrefetchPolicy();
policy.setQueuePrefetch(1);
factory.setPrefetchPolicy(policy);
return factory;
}
相关主题: