问题
I want that jms receives a message when one thread has handled a message (threadPool submits a callable). The messages are received by a master thread. Which way is better below:
I use spring 3.0.5 :
ApplicationContext context = new ClassPathXmlApplicationContext(
"application-context.xml");
jmsTemplate = (JmsTemplate) context.getBean("jmsTemplate");
destination = (Destination) context.getBean("destination");
_log4j.debug("ThreadSize in xml\t"
+ appConfig.getThumbCreatorThreadSize());
in master thread Way 1:
while (countFlag < 0) {
try {
TextMessage msg = (TextMessage) jmsTemplate
.receive(destination);
// prehandle ,then give to sub workers.
if (msg != null) {
_log4j.debug("JMSMessageID:\t" + msg.getJMSMessageID()
+ "\t" + msg.getText());
IConsumer thumbConsumerImpl = null;
thumbConsumerImpl = new ThumbConsumerTaskImpl(msg);
Future<List<ThumbCreatorInfo>> result = threadPool
.submit((Callable<List<ThumbCreatorInfo>>) thumbConsumerImpl);
}
} catch (IllegalArgumentException e) {
_log4j.warn(e.getMessage(), e);
} catch (JMSException e) {
_log4j.error("Please check the queue server!JMSException!", e);
} catch (Exception e) {
_log4j.error("", e);
}
}
in master thread Way 2:
TextMessage msg = (TextMessage) jmsTemplate.receive(destination);
do {
try {
// prehandle ,then give to sub workers.
if (msg != null) {
_log4j.debug("JMSMessageID:\t" + msg.getJMSMessageID()
+ "\t" + msg.getText());
IConsumer thumbConsumerImpl = null;
thumbConsumerImpl = new ThumbConsumerTaskImpl(msg);
Future<List<ThumbCreatorInfo>> result = threadPool
.submit((Callable<List<ThumbCreatorInfo>>) thumbConsumerImpl);
}
msg = (TextMessage) jmsTemplate.receive(destination);
} catch (IllegalArgumentException e) {
_log4j.warn(e.getMessage(), e);
} catch (JMSException e) {
_log4j.error("Please check the queue server!JMSException!", e);
} catch (Exception e) {
_log4j.error("", e);
}
} while (countFlag < 0);
回答1:
I'm not sure I get what you're trying to do. If you're trying to have multiple messages processed concurrently, get away from the JmsTemplate and use a DefaultMessageListenerContainer with concurrentConsumers. Also available via the JMS namespace.
For example, it seems that you could throw away all the code that you're showing in your question and use this instead:
<jms:listener-container concurrency="10">
<jms:listener destination="some.queue" ref="fooService" method="handleNewFoo"/>
</jms:listener-container>
That will automatically spawn up to 10 threads for concurrent message processing. When a message comes in, it will use one of the worker threads to call fooService.handleNewFoo(), where fooService is a bean in your Spring context.
Edit: I've created a sample project on github showing a basic Spring JMS setup. You can browse the source at https://github.com/zzantozz/testbed/tree/master/basic-spring-jms or just clone and run it:
git clone git://github.com/zzantozz/testbed.git tmp
cd tmp
mvn compile exec:java -Dexec.mainClass=rds.jms.Main -pl basic-spring-jms
There's a main class that starts a JMS broker and starts Spring. When Spring starts, it inits a bean that begins sending JMS messages. There's also a Spring message listener as I described above that consumes messages and passes them to the same bean that produces messages, which prints them to stdout.
回答2:
Why aren't you just using an MDP? Seems like you're recreating Spring functionality.
Example MDP:
public class MyMDP implements MessageListener {
public void onMessage(Message message) {
if (message instanceof TextMessage) {
...do whatever...
}
}
}
来源:https://stackoverflow.com/questions/6858038/jms-and-threadpool-problem