<!-- 创建工厂连接 --> <bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"> <property name="brokerURL" value="failover:(tcp://127.0.0.1:61616)?initialReconnectDelay=100" /> <property name="useAsyncSend" value="false" /> <property name="dispatchAsync" value="true" /> </bean> <bean id="pooledJmsConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory"> <constructor-arg ref="targetConnectionFactory" /> </bean> <bean id="queueDestinationIng" class="org.apache.activemq.command.ActiveMQQueue"> <constructor-arg> <value>order.ing</value> </constructor-arg> </bean> <!-- 消息监听器 --> <bean id="ingMessageListener" class="com.bypay.listener.IngListener" /> <!-- 消息监听容器 --> <bean id="jmsContainerIng" class="org.springframework.jms.listener.DefaultMessageListenerContainer"> <property name="connectionFactory" ref="pooledJmsConnectionFactory" /> <property name="destination" ref="queueDestinationIng" /> <property name="messageListener" ref="ingMessageListener" /> <property name="sessionTransacted" value="false"></property> <property name="concurrency" value="10-15"></property> </bean>
在上述配置中DefaultMessageListenerContainer主要的属性列表如下:
messageListener: 消息侦听器,必选属性。
taskExecutor: 任务调度器,可以使用线程池开并发的消费消息。如果开发者不指定,spring将会采用默认的TaskExecutor(SimpleAsyncTaskExecutor,类似于CachedThreadPool)。
concurrentConsumers: 消费者的最大个数,因为在spring中messageListener实例是单例的,比如上文中的orderListener(备注:它实现了MessageListener接口),所以spring-jms不能自作主张的创建多个messageListener实例来并发消费。所以spring在内部,创建了多个MessageConsumer实例,并使用consumer.receive()方法以阻塞的方式来获取消息,当获取消息后,在执行messageListener.onMessage()方法;concurrentConsumers属性就是为了指定spring内部可以创建MessageConsumer的最大个数;当messageConsumer实例被创建后,将会封装在一个Runner接口并交给taskExecutor来调度;如果consumer在一直没有收到消息,则会被置为“idle”并从consumer列表中移除;如果所有的consumer都处于active状态,则会创建新的consumer实例直到达到maxConcurrentConsumers个数上限。通常taskExecutor的线程池容量稍大于concurrentConsumer。
maxMessagesPerTask: 每个consumer所消费的消息个数,因为每个consumer都会独占一个Thread[consumer.receive()是阻塞的],当consumer消费maxMessagesPerTask个消息后,它就会退出线程,由taskExecutor重新调度。
receiveTimeout: 内部的consumer在receive方法中阻塞的时间。默认为1秒。
recoveryInterval: 当消息消费时,底层connection异常而无法继续,listener需要等待恢复的时间间隔。默认为5000ms。
concurrency: “concurrentConsumers”与“maxConcurrentConsumers”两个参数的简写方式,格式为“5-10”,则表示concurrentConsumers为5,maxConcurrentConsumers为10。
sessionTransacted: Session是否为事务类型。默认为false。
messageSelector: 消息选择器。如果你希望此listener只接受某种特性的消息,可以通过指定selector的方式来过滤消息。
pubSubDomain: 此消费通道是否为Topic,默认为“false”。所有与Topic有关的属性,只有在pubSubDomain为true的情况下生效。
pubSubNoLocal: 对于Topic而言,此消费者是否消费本地消息。所谓本地消息,就是当Consumer与Producer公用底层一个Connection时,那么Producer发送的消息,相对于此Consumer就是本地消息。在pubSubDomain为true时有效。
subscriptionDurable: 是否为“耐久性”订阅者。在pubSubDomain为true时有效。默认为false。
durableSubscriptionName: 耐久订阅者名称,每个clientId下可以有多个耐久订阅者,但是他们必须有不同的名字。默认为className。
errorHandler: 当listener.onMessage方法抛出异常时,异常该如何处理。
autoStartup: 消费者是否自动启动,默认为true,那么在messageContainer实例化后,将会启动consumer(即调用Connection.start());如果为false,那些开发者需要在合适的时机手动启动。
clientId: 对于Topic订阅者而言,此参数必备。
sessionAcknowledgeMode: ACK MODE,默认为AUTO。spring-jms做了一件非常遗憾的事情,如果指定了sessionTransacted为true,那么在调用listener.onMessage()方法之后,则会立即提交事务(session.commit()),即使开发者使用了sessionAwareMessageListener,所以开发者无法实现基于事务的“批量”确认机制。如果开发者指定为CLIENT_ACK,那么spring-JMS将会在onMessage方法返回后立即调用message.acknowlege()方法,所以开发者自己是否确认以及何时确认,将没有意义,如果不希望spring来确认消息,只能在onMessage方法中通过抛出异常的方式。 其中“1”表示AUTO_ACKNOWLEDGE,“2”为CLIENT_ACKNOWLEDGE = 2,“3”为 DUPS_OK_ACKNOWLEDGE = 3。