SpringBoot整合IBM MQ,多个队列管理器通信

说明:本项目开发前提是,在本地windows机器上搭建了MQ,并建立好发送队列管理器,本地队列,远程队列,发送通道;在阿里云服务器上也搭建了MQ,建立了接收队列管理器,接收通道。具体步骤见本人之前的博客。地址:https://blog.csdn.net/qq_34569497/article/details/81197910

此处,模拟场景是,本地Windows机器放入测试消息后,在springboot项目中通过程序连接阿里云MQ并接收到消息。同一台机器同一个队列管理器上发送和接收消息,见本人之前的博客。地址:https://blog.csdn.net/qq_34569497/article/details/81184177。

Windows服务器上MQ发送消息,通过springboot接收阿里云服务器上消息。

由于此处只是测试通过程序接收消息,故代码只有接收部分。

1.使用java连接阿里云MQ接收消息

1.1 项目pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.ibmmq</groupId>
	<artifactId>ibmmq</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>ibmmq</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.3.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jms</artifactId>
		</dependency>

		<dependency>
			<groupId>javax.jms</groupId>
			<artifactId>javax.jms-api</artifactId>
		</dependency>

		<dependency>
			<groupId>com.ibm.mq</groupId>
			<artifactId>com.ibm.mq.allclient</artifactId>
			<version>9.0.5.0</version>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

1.2 启动类IbmmqApplication.java

package com.ibmmq.ibmmq;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@SpringBootApplication
@EnableTransactionManagement
public class IbmmqApplication {

	public static void main(String[] args) {
		SpringApplication.run(IbmmqApplication.class, args);
	}
}

1.3 IBM MQ 基本配置文件 application.properties

project.mq.host=120.79.239.214
project.mq.port=1416
project.mq.queue-manager=QM_RECEIVE
project.mq.channel=SEND_RECEIVE_CHL
#project.mq.channel=SYSTEM.DEF.SVRCONN 
#project.mq.channel=SEND_RECEIVE_CONN
project.mq.username=mqm
project.mq.password=lmf000
#project.mq.password=lmf888888
project.mq.receive-timeout=20000

1.4基本配置处理类JmsConfig.java

package com.ibmmq.ibmmq.test;

import org.springframework.beans.factory.annotation.Value;
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.connection.UserCredentialsConnectionFactoryAdapter;
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;

@Configuration
public class JmsConfig {   
    @Value("${project.mq.host}")
    private String host;
    @Value("${project.mq.port}")
    private Integer port;
    @Value("${project.mq.queue-manager}")
    private String queueManager;
    @Value("${project.mq.channel}")
    private String channel;
    @Value("${project.mq.username}")
    private String username;
    @Value("${project.mq.password}")
    private String password;
    @Value("${project.mq.receive-timeout}")
    private long receiveTimeout;
    @Bean
    public MQQueueConnectionFactory mqQueueConnectionFactory() {
        MQQueueConnectionFactory mqQueueConnectionFactory = new MQQueueConnectionFactory();
        mqQueueConnectionFactory.setHostName(host);
        try {
        	mqQueueConnectionFactory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
            mqQueueConnectionFactory.setCCSID(1208);
            mqQueueConnectionFactory.setChannel(channel);
            mqQueueConnectionFactory.setPort(port);
            mqQueueConnectionFactory.setQueueManager(queueManager);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return mqQueueConnectionFactory;
    }
    @Bean
    UserCredentialsConnectionFactoryAdapter userCredentialsConnectionFactoryAdapter(MQQueueConnectionFactory mqQueueConnectionFactory) {
        UserCredentialsConnectionFactoryAdapter userCredentialsConnectionFactoryAdapter = new UserCredentialsConnectionFactoryAdapter();
        userCredentialsConnectionFactoryAdapter.setUsername(username);
        userCredentialsConnectionFactoryAdapter.setPassword(password);
        userCredentialsConnectionFactoryAdapter.setTargetConnectionFactory(mqQueueConnectionFactory);
        return userCredentialsConnectionFactoryAdapter;
    }
    @Bean
    @Primary
    public CachingConnectionFactory cachingConnectionFactory(UserCredentialsConnectionFactoryAdapter userCredentialsConnectionFactoryAdapter) {
        CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory();
        cachingConnectionFactory.setTargetConnectionFactory(userCredentialsConnectionFactoryAdapter);
        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;
    }
}

1.5 接收消息类ReceiveMessage.java

(继承MessageListenerAdapter类且使用@JmsListener注解进行监听)

注意:此处若只使用@JmsListener注解监听,会出现监听消息获取不及时或者获取不到消息的情况,加上MessageListenerAdapter后便不会出现

package com.ibmmq.ibmmq.test;

import javax.jms.Message;

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;

//消息消费者的类上必须加上@Component,或者是@Service,这样的话,消息消费者类就会被委派给Listener类,原理类似于使用SessionAwareMessageListener以及MessageListenerAdapter来实现消息驱动POJO
@Component
public class ReceiveMessage extends MessageListenerAdapter{
	@Autowired
	JmsOperations jmsOperations;

    @Override
    @JmsListener(destination = "RLQ")
    public void onMessage(Message message) {
        String messageBody = new String(message.toString());
    	System.out.println("成功监听Q1消息队列,传来的值为:" + messageBody);
    }
}

1.6启动项目后报错

2018-07-26 15:31:40.504  INFO 12380 --- [enerContainer-1] o.s.j.l.DefaultMessageListenerContainer  : JMS message listener invoker needs to establish shared Connection
2018-07-26 15:31:40.622 ERROR 12380 --- [enerContainer-1] o.s.j.l.DefaultMessageListenerContainer  : Could not refresh JMS Connection for destination 'RLQ' - retrying using FixedBackOff{interval=5000, currentAttempts=0, maxAttempts=unlimited}. Cause: JMSWMQ0018: 连接至队列管理器“QM_RECEIVE”失败,连接方式为“Client”,主机名为“xxx.xx.xxx.xxx(1416)”。; nested exception is com.ibm.mq.MQException: JMSCMQ0001: IBM MQ 调用失败,完成代码为“2”(“MQCC_FAILED”),原因码为“2539”(“MQRC_CHANNEL_CONFIG_ERROR”)。

1.7 错误解决

在网上查找了很多资料,最后,有篇文章说将配置中的project.mq.channel=SEND_RECEIVE_CHL改为以下即可,

project.mq.channel=SYSTEM.DEF.SVRCONN

改完后,确实程序可以正常监听并接收消息。但是,根据文章https://blog.csdn.net/haitaofeiyang/article/details/46897323中将到的“注意:我们不建议用户连接SYSTEM.DEF.*通道。这些系统定义的通道是定义其它用户通道的模板。不建议用户使用SYSTEM.DEF.*和SYSTEM.AUTO.*通道。”。

那么,要如何使用自定义的通道呢。

所以就想到了对比自己建立的通道和系统自带的通道,发现:

系统自带:

dis chl(SYSTEM.DEF.SVRCONN)
     5 : dis chl(SYSTEM.DEF.SVRCONN)
AMQ8414: Display Channel details.
   CHANNEL(SYSTEM.DEF.SVRCONN)             CHLTYPE(SVRCONN)
   ALTDATE(2018-07-25)                     ALTTIME(09.41.50)
   CERTLABL( )                             COMPHDR(NONE)
   COMPMSG(NONE)                           DESCR( )
   DISCINT(0)                              HBINT(300)
   KAINT(AUTO)                             MAXINST(999999999)
   MAXINSTC(999999999)                     MAXMSGL(4194304)
   MCAUSER( )                              MONCHL(QMGR)
   RCVDATA( )                              RCVEXIT( )
   SCYDATA( )                              SCYEXIT( )
   SENDDATA( )                             SENDEXIT( )
   SHARECNV(10)                            SSLCAUTH(REQUIRED)
   SSLCIPH( )                              SSLPEER( )

自定义通道:

dis chl(SEND_RECEIVE_CHL)
     6 : dis chl(SEND_RECEIVE_CHL)
AMQ8414: Display Channel details.
   CHANNEL(SEND_RECEIVE_CHL)               CHLTYPE(RCVR)
   ALTDATE(2018-07-25)                     ALTTIME(09.51.03)
   BATCHSZ(50)                             CERTLABL( )
   COMPHDR(NONE)                           COMPMSG(NONE)
   DESCR( )                                HBINT(300)
   KAINT(AUTO)                             MAXMSGL(4194304)
   MCAUSER( )                              MONCHL(QMGR)
   MRDATA( )                               MREXIT( )
   MRRTY(10)                               MRTMR(1000)
   MSGDATA( )                              MSGEXIT( )
   NPMSPEED(FAST)                          PUTAUT(DEF)
   RCVDATA( )                              RCVEXIT( )
   RESETSEQ(NO)                            SCYDATA( )
   SCYEXIT( )                              SENDDATA( )
   SENDEXIT( )                             SEQWRAP(999999999)
   SSLCAUTH(REQUIRED)                      SSLCIPH( )
   SSLPEER( )                              STATCHL(QMGR)
   TRPTYPE(TCP)                            USEDLQ(YES)

对比可见,两者最大的不同即CHLTYPE,自定义的通道为RCVR,而系统自带的通道为SVRCONN。通过百度IBM MQ CHLTYPE类型,知道原来SVRCONN代表服务器连接通道,而RCVR代表接收方通道。

 服务器连接通道就是给MQ客户端连接进来的一个标识入口,它和其他通道不一样,它是不需要启动的,如果有MQ客户端成功地通过这个服务器连接通道连接进来,它的状态就是活动的了。因此我们需要在阿里云上对应的队列管理器中建立服务器连接通道后,才可通过java进行连接。

创建服务器连接通道:

DEFINE CHANNEL(SEND_RECEIVE_CONN) CHLTYPE(SVRCONN) TRPTYPE(TCP) 


要为受 SSL 保护的 IBM MessageSight 连接创建服务器连接通道:

DEFINE CHANNEL(SEND_RECEIVE_CONN) CHLTYPE(SVRCONN) TRPTYPE(TCP) SSLCIPH(cipherSpec)

创建好后,将java配置文件中channel改为:project.mq.channel=SEND_RECEIVE_CONN

再次启动服务,发现不再报错。

1.8 测试结果

本地远程中放入测试消息:

服务中监听到的消息:

成功监听Q1消息队列,传来的值为:
  JMSMessage class: jms_text
  JMSType:          null
  JMSDeliveryMode:  1
  JMSDeliveryDelay: 0
  JMSDeliveryTime:  0
  JMSExpiration:    0
  JMSPriority:      0
  JMSMessageID:     ID:414d5120514d5f53454e442020202020d71a595b24ad7a02
  JMSTimestamp:     1532596311700
  JMSCorrelationID: null
  JMSDestination:   null
  JMSReplyTo:       null
  JMSRedelivered:   false
    JMSXAppID: Windows\bin64\MQExplorer.exe
    JMSXDeliveryCount: 1
    JMSXUserID: lmf         
    JMS_IBM_Character_Set: UTF-8
    JMS_IBM_Encoding: 546
    JMS_IBM_Format: MQSTR   
    JMS_IBM_MsgType: 8
    JMS_IBM_PutApplType: 11
    JMS_IBM_PutDate: 20180726
    JMS_IBM_PutTime: 09115170
test my message

测试成功。

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
在Spring Boot中整合IBM MQ并同时监听多个管道,可以使用IBM MQ的Java API和Spring Boot的消息监听器来实现。 1. 添加IBM MQ的Java API依赖 在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>com.ibm.mq</groupId> <artifactId>mq-jms-spring-boot-starter</artifactId> <version>2.0.0</version> </dependency> ``` 2. 配置IBM MQ连接信息 在application.properties文件中配置IBM MQ连接信息,如下所示: ``` ibm.mq.queueManager=QMGR ibm.mq.channel=CHANNEL ibm.mq.connName=HOSTNAME(PORT) ibm.mq.user=USERNAME ibm.mq.password=PASSWORD ``` 其中,QUEUE_MANAGER是IBM MQ队列管理器名称,CHANNEL是用于连接队列管理器的通道名称,CONN_NAME是IBM MQ的主机名和端口号,USER和PASSWORD是连接IBM MQ所需的凭据。 3. 配置消息监听器 在Spring Boot中,可以使用@JmsListener注解来创建消息监听器。为了同时监听多个管道,可以在注解中指定多个目标队列的名称,如下所示: ```java @JmsListener(destination = {"QUEUE1", "QUEUE2"}) public void onMessage(Message message) { // 处理消息 } ``` 4. 启动应用程序 最后,可以启动应用程序并开始监听多个管道上的消息。当有消息到达任何一个队列时,消息监听器都会被触发,并处理消息。 总结: 使用Spring Boot和IBM MQ的Java API,可以轻松地实现对多个管道的消息监听。只需添加IBM MQ的Java API依赖,配置连接信息和消息监听器,就可以在Spring Boot应用程序中同时监听多个管道上的消息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值