我使用spring + MQ + Websphere Application Server。
我想异步使用来自MQ的消息,并合并消息以使消息列表易于在每次提交中将N个实体持久保存到数据库。 (不必过多地提交我的目标Oracle数据库)
我使用DefaultMessageListenerContainer并同步了onMessage方法以添加消息(直到批处理大小),然后创建线程以等待条件满足(时间/大小)并将消息推送到另一个线程业务逻辑和数据库保持不变。
线程启动的条件:
一旦第一条消息到达onMessage方法内部,线程必须等待以查看在1000毫秒内收到25条消息,如果1000毫秒内未到达25条消息,它将可用的消息数推送到另一个线程。
问题:
我看到线程仅在服务器状态启动期间启动,而不是在首次调用onMessage方法时启动。
有任何建议/其他方法可以实现从Queue收集消息吗?
applicationContext.xml
<bean id="myMessageListener" class="org.mypackage.MyMessageListener">
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="destinationName" ref="queue"/>
<property name="messageListener" ref="myMessageListener"/>
<property name ="concurrentConsumers" value ="10"/>
<property name ="maxConcurrentConsumers" value ="50"/>
</bean>
监听器:
package org.mypackage.MyMessageListener;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import org.mypackage.service.MyService;
public class MyMessageListener implements MessageListener {
private volatile long startTime = 0;
private volatile int messageCount;
private volatile List<String> messagesFromQueue = null;
private int batchSize = 25;
private long maximumBatchWaitTime = 1000;
@Autowired
private MyService myService;
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
boolean threadRun = true;
while (threadRun) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
System.out.println("InterruptedException is caught inside run method");
}
if ((messageCount >0 && messageCount == batchSize)) {
System.out.println("----Batch size Reached----");
threadRun = false;
processMsgsFromQueue(messagesFromQueue);
} else {
if (maximumBatchWaitTime > (System.currentTimeMillis() - startTime)) {
System.out.println("----Time limit is not reached----");
threadRun = true;
} else {
threadRun = false;
System.out.println("----Time limit is reached----");
processMsgsFromQueue(messagesFromQueue);
}
}
}
}
});
{
thread.start();
}
@Override
public synchronized void onMessage(Message message) {
if (messageCount == 0) {
startTime = System.currentTimeMillis();
messagesFromQueue = new ArrayList<String>();
System.out.println("----First Message Arrived at----"+startTime);
}
try {
messageCount++;
TextMessage tm = (TextMessage) message;
String msg = tm.getText();
messagesFromQueue.add(msg);
if (messageCount == 0) {
thread.start();
}
} catch (JMSException e1) {
e1.printStackTrace();
}
}
private void processMsgsFromQueue(List<String> messageFromQueue) {
System.out.println("Inside processMsgsFromQueue");
messageCount = 0;
messagesFromQueue = null;
if(!messageFromQueue.isEmpty()) {
this.myService.insertMsgsFromQueueToDB(messageFromQueue);
}
}
}
答案 0 :(得分:0)
您还需要同步对messagesFromQueue的访问。
List messagesFromQueue = Collections.synchronizedList(new ArrayList());
...
synchronized (messagesFromQueue) {
Iterator i = messagesFromQueue.iterator(); // Must be in synchronized block
while (i.hasNext())
...
}
在每次调用processMsgsFromQueue时,您都会遇到NullPointerException!
private void processMsgsFromQueue(List<String> messageFromQueue) {
System.out.println("Inside processMsgsFromQueue");
messageCount = 0;
messagesFromQueue = null;
if(!messageFromQueue.isEmpty()/*messageFromQueue is null!!*/) {
this.myService.insertMsgsFromQueueToDB(messageFromQueue);
}
}
最好保留消息,并在确定提交后清除列表并重置计数器。
package org.mypackage.MyMessageListener;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import org.mypackage.service.MyService;
public class MyMessageListener implements MessageListener {
private volatile long startTime = 0;
private volatile int messageCount;
private volatile List<String> messagesFromQueue = null;
private int batchSize = 25;
private long maximumBatchWaitTime = 1000;
@Autowired
private MyService myService;
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
boolean threadRun = true;
while (threadRun) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
System.out.println("InterruptedException is caught inside run method");
}
if ((messageCount >0 && messageCount == batchSize)) {
System.out.println("----Batch size Reached----");
threadRun = false;
processMsgsFromQueue(messagesFromQueue);
} else {
if (maximumBatchWaitTime > (System.currentTimeMillis() - startTime)) {
System.out.println("----Time limit is not reached----");
threadRun = true;
} else {
threadRun = false;
System.out.println("----Time limit is reached----");
processMsgsFromQueue(messagesFromQueue);
}
}
}
}
});
@Override
public synchronized void onMessage(Message message) {
if (messageCount == 0) {
startTime = System.currentTimeMillis();
messagesFromQueue = new ArrayList<String>();
System.out.println("----First Message Arrived at----"+startTime);
}
try {
messageCount++;
TextMessage tm = (TextMessage) message;
String msg = tm.getText();
messagesFromQueue.add(msg);
if (thread.getState() == Thread.State.NEW) {
thread.start();
}
} catch (JMSException e1) {
e1.printStackTrace();
}
}
private void processMsgsFromQueue(List<String> messageFromQueue) {
System.out.println("Inside processMsgsFromQueue");
if(!messageFromQueue.isEmpty()) {
this.myService.insertMsgsFromQueueToDB(messageFromQueue);
}
messageCount = 0;
messagesFromQueue = null;
}
}