背景:服务端提供13个消息队列,做为客户端需要从队列中消费消息,刚开始使用死循环去消费,消费到一定量级后提示2044,扒了一下资料,发现可能是因为循环次数过多导致,然后开始研究队列监听方式来获取数据。
使用队列监听需要在原来基础上新建两个类,直接上代码:
导入jar包(其中和MQ相关的jar包以自己的为准,不要直接使用我的,我的MQ的jar包中7.X版本是服务端提供的):
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
</dependency>
<dependency>
<groupId>javax.jms</groupId>
<artifactId>javax.jms-api</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>com.ibm.mq</groupId>
<artifactId>mq</artifactId>
<version>7.0.1.3</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/com.ibm.mq-7.0.1.3.jar</systemPath>
</dependency>
<dependency>
<groupId>com.ibm.mq</groupId>
<artifactId>commonservices</artifactId>
<version>7.0.1.3</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/com.ibm.mq.commonservices-7.0.1.3.jar</systemPath>
</dependency>
<dependency>
<groupId>com.ibm.mq</groupId>
<artifactId>com.ibm.mq.allclient</artifactId>
<version>9.0.5.0</version>
</dependency>
<dependency>
<groupId>com.ibm.mq</groupId>
<artifactId>headers</artifactId>
<version>7.0.1.3</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/com.ibm.mq.headers-7.0.1.3.jar</systemPath>
</dependency>
<dependency>
<groupId>com.ibm.mq</groupId>
<artifactId>jmqi</artifactId>
<version>7.0.1.3</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/com.ibm.mq.jmqi-7.0.1.3.jar</systemPath>
</dependency>
<dependency>
<groupId>com.ibm.mq</groupId>
<artifactId>pcf</artifactId>
<version>7.0.1.3</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/com.ibm.mq.pcf-7.0.1.3.jar</systemPath>
</dependency>
<dependency>
<groupId>commons</groupId>
<artifactId>codec</artifactId>
<version>1.6</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/commons-codec-1.6.jar</systemPath>
</dependency>
MQConfig.class(MQ配置):
package com.zpd.listener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jms.connection.CachingConnectionFactory;
import org.springframework.jms.connection.JmsTransactionManager;
import org.springframework.jms.core.JmsOperations;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.transaction.PlatformTransactionManager;
import com.ibm.mq.jms.MQQueueConnectionFactory;
import com.ibm.msg.client.wmq.WMQConstants;
import lombok.extern.slf4j.Slf4j;
@Configuration
@Slf4j
public class JmsConfig {
//此处将MQ队列配置的信息直接写到了代码中,如果写在了配置文件中,可以通过@Value来获取
//@Value("${project.mq.host}")
private String host = "...";
//@Value("${project.mq.port}")
private Integer port = 6000;
//@Value("${project.mq.ccsid}")
private Integer ccsid = 1208;
//@Value("${project.mq.queue-manager}")
private String queueManager = "...";
//@Value("${project.mq.channel}")
private String channel = "...";
//@Value("${project.mq.receive-timeout}")
private long receiveTimeout = 20000L;
@Bean
public MQQueueConnectionFactory mqQueueConnectionFactory() {
MQQueueConnectionFactory mqQueueConnectionFactory = new MQQueueConnectionFactory();
mqQueueConnectionFactory.setHostName(host);
try {
mqQueueConnectionFactory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
mqQueueConnectionFactory.setCCSID(ccsid);
mqQueueConnectionFactory.setChannel(channel);
mqQueueConnectionFactory.setPort(port);
mqQueueConnectionFactory.setQueueManager(queueManager);
} catch (Exception e) {
e.printStackTrace();
}
return mqQueueConnectionFactory;
}
//此处因为消息队列不需要通过用户名和密码去获取,所以直接将mqQueueConnectionFactory注入到了缓存配置中,如果需要用到用户名和密码,可以去参考其他资料
@Bean
@Primary
public CachingConnectionFactory cachingConnectionFactory(MQQueueConnectionFactory mqQueueConnectionFactory) {
CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory();
cachingConnectionFactory.setTargetConnectionFactory(mqQueueConnectionFactory);
cachingConnectionFactory.setSessionCacheSize(500);
cachingConnectionFactory.setReconnectOnException(true);
return cachingConnectionFactory;
}
@Bean
public PlatformTransactionManager jmsTransactionManager(CachingConnectionFactory cachingConnectionFactory) {
JmsTransactionManager jmsTransactionManager = new JmsTransactionManager();
jmsTransactionManager.setConnectionFactory(cachingConnectionFactory);
return jmsTransactionManager;
}
//如果只是获取消息,此处无需配置
@Bean
public JmsOperations jmsOperations(CachingConnectionFactory cachingConnectionFactory) {
JmsTemplate jmsTemplate = new JmsTemplate(cachingConnectionFactory);
jmsTemplate.setReceiveTimeout(receiveTimeout);
return jmsTemplate;
}
}
MQListener.class(MQ监听):
package com.zpd.listener;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.TextMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.jms.core.JmsOperations;
import org.springframework.jms.listener.adapter.MessageListenerAdapter;
import org.springframework.stereotype.Component;
import com.zpd.service.DataService;
import com.zpd.utils.JDBCUtils;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Component
public class MQListener extends MessageListenerAdapter {
private static final DataService dataService = new DataService();
@Autowired
JmsOperations jmsOperations;
/*
* BS002队列监听
* @author chengjunyu
* @date 2019-11-05 12:48:57
* @param
*/
@JmsListener(destination = "BS002")
public void onMessageBS002(Message message) {
String msgStr ="";
String sourceFrom = "BS002";
try { //JmsListener收到消息后,会自动封装成自己特有的数据格式,可以用TextMessage来解析原始消息
TextMessage msg = (TextMessage) message;
msgStr = msg.getText();
log.info("从队列BS002中获取的消息内容:" + msgStr);
//将消息写入/zpd/sc_interface/路径下
saveMessageToFile(sourceFrom, msgStr);
dataService.getMessageFromBS002(msgStr);
} catch (JMSException e) {
log.error("从队列BS002中接收消息异常!", e);
} catch (Exception e) {
saveException(sourceFrom, msgStr, e);
}
}
/*
* BS004队列监听
*/
@JmsListener(destination = "BS004")
public void onMessageBS004(Message message) {
String msgStr ="";
String sourceFrom = "BS004";
try { //JmsListener收到消息后,会自动封装成自己特有的数据格式,可以用TextMessage来解析原始消息
TextMessage msg = (TextMessage) message;
msgStr = msg.getText();
log.info("从队列BS004中获取的消息内容:" + msgStr);
//将消息写入/zpd/sc_interface/路径下
saveMessageToFile(sourceFrom, msgStr);
dataService.getMessageFromBS004(msgStr);
} catch (JMSException e) {
log.error("从队列BS004中接收消息异常!", e);
} catch (Exception e) {
saveException(sourceFrom, msgStr, e);
}
}
/*
* BS005队列监听
*/
@JmsListener(destination = "BS005")
public void onMessageBS005(Message message) {
String msgStr ="";
String sourceFrom = "BS005";
try { //JmsListener收到消息后,会自动封装成自己特有的数据格式,可以用TextMessage来解析原始消息
TextMessage msg = (TextMessage) message;
msgStr = msg.getText();
log.info("从队列BS005中获取的消息内容:" + msgStr);
//将消息写入/zpd/sc_interface/路径下
saveMessageToFile(sourceFrom, msgStr);
dataService.getMessageFromBS005(msgStr);
} catch (JMSException e) {
log.error("从队列BS005中接收消息异常!", e);
} catch (Exception e) {
saveException(sourceFrom, msgStr, e);
}
}
/*
* 保存异常信息到数据库中
* @Author chengjunyu
* @date 2019-11-05 12:56:35
*/
public void saveException(String sourceFrom, String msgStr, Exception e) {
Connection connection = JDBCUtils.getConnection();
PreparedStatement pstmt = null;
String exceptionSql = "insert into run_log values (null,?,?,?,'"+dataService.getNowTime()+"')";
try {
pstmt = connection.prepareStatement(exceptionSql);
pstmt.setString(1, sourceFrom);
pstmt.setString(2, msgStr);
pstmt.setString(3, getExceptionInfo(e));
pstmt.execute();
} catch (SQLException e2) {
log.info(sourceFrom + "保存错误信息异常:" + e2);
} finally {
if(pstmt != null) {
try {
pstmt.close();
} catch (SQLException e1) {
log.info(sourceFrom + "关闭预编译失败,原因为:" + e1);
}
}
if(connection != null) {
try {
connection.close();
} catch (SQLException e1) {
log.info(sourceFrom + "关闭数据库连接失败,原因为:" + e1);
}
}
}
}
/*
* 将异常信息转换为字符串
* @Author chengjunyu
* @date 2019-11-05 12:56:59
*/
public String getExceptionInfo(Throwable t) {
StringWriter stringWriter= new StringWriter();
PrintWriter writer= new PrintWriter(stringWriter);
t.printStackTrace(writer);
StringBuffer buffer= stringWriter.getBuffer();
return buffer.toString();
}
/*
* 将消息内容保存到磁盘文件上
* @Author chengjunyu
* @date 2019-11-05 12:57:28
*/
public void saveMessageToFile(String sourceFrom, String msgStr) {
try {
String dirPathOuter = "/zpd/sc_interface/" + sourceFrom;
File dirOuter = new File(dirPathOuter);
if(!dirOuter.exists()) {
dirOuter.mkdirs();
}
String dirPathInner = dirPathOuter + "/" + getDate();
File dirInner = new File(dirPathInner);
if(!dirInner.exists()) {
dirInner.mkdirs();
}
String filePath = dirPathInner + "/" + sourceFrom + "_" + getTime() + ".xml";
File txt = new File(filePath);
if (!txt.exists()) {
txt.createNewFile();
}
byte bytes[] = new byte[512];
bytes = msgStr.getBytes();
FileOutputStream fos = new FileOutputStream(txt);
fos.write(bytes);
fos.flush();
fos.close();
} catch (IOException e) {
log.info("保存信息到文件产生异常:" + e);
}
}
public String getDate() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
Date date = new Date();
String dateStr = sdf.format(date);
return dateStr;
}
public String getTime() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
Date date = new Date();
String dateStr = sdf.format(date);
return dateStr;
}
}