使用Spring-boot创建共享持久订阅者

时间:2018-07-31 06:39:28

标签: spring spring-boot ibm-mq publish-subscribe spring-jms

我想用spring-boot和IBM MQ创建一个共享持久的订户。我已经做了一个持久的订阅者,但是共享订阅失败了。

调试程序时,我发现了空指针异常问题

java.lang.NoSuchMethodError: javax.jms.Session.createSharedDurableConsumer(Ljavax/jms/Topic;Ljava/lang/String;Ljava/lang/String;)Ljavax/jms/MessageConsumer;

内部类 AbstractMessageListenerContainer 中,方法 createConsumer 。这是因为它尝试调用session.createSharedDurableConsumerMethod,其中会话对象为javax.jms.Session和IntelliJ将其指向库 geronimo-jms_1.1_spec-1.1.1.jar

我的pom.xml使用的是JMS 2.0:

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

这是Java代码:

import com.ibm.mq.jms.*;

...

public class JmsConfig {

...

@Bean
public MQTopicConnectionFactory mqTopicConnectionFactory(){
    MQTopicConnectionFactory factory = new MQTopicConnectionFactory();
    try{
        factory.setHostName(mqHostname);
        factory.setChannel(mqChannel);
        factory.setPort(Integer.parseInt(mqPort));
        factory.setQueueManager(mqQManager);
        factory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
        factory.setClientReconnectTimeout(0);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return factory;
}

@Bean
@Primary
UserCredentialsConnectionFactoryAdapter userCredentialsConnectionFactoryAdapter(MQTopicConnectionFactory mqTopicConnectionFactory) {
    UserCredentialsConnectionFactoryAdapter userCredentialsConnectionFactoryAdapter = new UserCredentialsConnectionFactoryAdapter();
    userCredentialsConnectionFactoryAdapter.setTargetConnectionFactory(mqTopicConnectionFactory);
    userCredentialsConnectionFactoryAdapter.setUsername(mqUsername);
    if(!mqPassword.equals("")) {
        userCredentialsConnectionFactoryAdapter.setPassword(mqPassword);
    }
    return userCredentialsConnectionFactoryAdapter;
}

@Bean
public CachingConnectionFactory cachingConnectionFactory(UserCredentialsConnectionFactoryAdapter userCredentialsConnectionFactoryAdapter) {
    CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory();
    cachingConnectionFactory.setTargetConnectionFactory(userCredentialsConnectionFactoryAdapter);
    cachingConnectionFactory.setSessionCacheSize(1000);
    cachingConnectionFactory.setReconnectOnException(true);
    return cachingConnectionFactory;
}


@Bean
public JmsOperations jmsOperations(CachingConnectionFactory cachingConnectionFactory) {
    JmsTemplate jmsTemplate = new JmsTemplate(cachingConnectionFactory);
    jmsTemplate.setPubSubDomain(true);
    jmsTemplate.setReceiveTimeout(2000);
    return jmsTemplate;
}

@Bean
public JmsListenerContainerFactory<?> topicListenerFactory(ConnectionFactory connectionFactory, DefaultJmsListenerContainerFactoryConfigurer configurer) {

    DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
    configurer.configure(factory, connectionFactory);
    factory.setPubSubDomain(true);//must follow the configurer.configure(), because it will set the factory as default as connectionFactory
    factory.setConcurrency("1");
    factory.setSubscriptionShared(true);
    factory.setSubscriptionDurable(true);
    factory.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
    factory.setClientId(mqClientID);
    return factory;
}
}

是否缺少任何配置,或者需要重写该方法来管理Session对象,以便它可以创建持久共享的连接?

1 个答案:

答案 0 :(得分:0)

最后,我弄清楚了为什么该程序使用JMS1.1。这是因为程序的另一部分从pom加载了AWS SQS库,并且该库将JMS1.1(geronimo-jms_1.1_spec-1.1.1.jar)用于ActiveMQ。

因此,我在pom中为AWS SQS库添加了排除项,以防止它覆盖JMS2.0库。