java - ActiveMQ Artemis 和 5.x 监听器同时 - NullPointerException
问题描述
我有一个旧版 Spring 4.2.1.RELEASE 应用程序,它作为侦听器连接到 ActiveMQ 5.x,现在我们正在添加到 ActiveMQ Artemis 的连接性。对于 Artemis,我们使用持久订阅,因为我们不希望在订阅者关闭和共享订阅时在主题上丢失消息,因为我们希望选择集群或使用并发来异步处理订阅中的消息。我有单独ConnectionFactory
的 s 和ListenerContainer
s,但是从这个WARN
不断重复的日志看来,由于以下 NPE,Artemis DMLC 无法启动:
java.lang.NullPointerException
at org.springframework.jms.listener.AbstractMessageListenerContainer.createConsumer(AbstractMessageListenerContainer.java:856)
at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.createListenerConsumer(AbstractPollingMessageListenerContainer.java:213)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.initResourcesIfNecessary(DefaultMessageListenerContainer.java:1173)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1149)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1142)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:1039)
at java.lang.Thread.run(Unknown Source)
从表面上看,它似乎找不到方法createSharedDurableConsumer
。查看我拥有的AbstractMessageListenerContainer,第 856 行正在调用 method.invoke
/** The JMS 2.0 Session.createSharedDurableConsumer method, if available */
private static final Method createSharedDurableConsumerMethod = ClassUtils.getMethodIfAvailable(
Session.class, "createSharedDurableConsumer", Topic.class, String.class, String.class);
...
Method method = (isSubscriptionDurable() ?
createSharedDurableConsumerMethod : createSharedConsumerMethod);
try {
return (MessageConsumer) method.invoke(session, destination, getSubscriptionName(), getMessageSelector());
}
阿尔忒弥斯配置:
@Configuration
public class ArtemisConfig {
@Autowired
private Environment env;
@Bean
public ConnectionFactory artemisConnectionFactory() {
ActiveMQConnectionFactory artemisConnectionFactory = ActiveMQJMSClient
.createConnectionFactoryWithHA(JMSFactoryType.CF, createTransportConfigurations());
artemisConnectionFactory.setUser(env.getRequiredProperty("artemis.username"));
artemisConnectionFactory.setPassword(env.getRequiredProperty("artemis.password"));
artemisConnectionFactory.setCallTimeout(env.getRequiredProperty("artemis.call.timeout.millis", Long.class));
artemisConnectionFactory.setConnectionTTL(env.getRequiredProperty("artemis.connection.ttl.millis", Long.class));
artemisConnectionFactory
.setCallFailoverTimeout(env.getRequiredProperty("artemis.call.failover.timeout.millis", Long.class));
artemisConnectionFactory.setInitialConnectAttempts(
env.getRequiredProperty("artemis.connection.attempts.initial", Integer.class));
artemisConnectionFactory
.setReconnectAttempts(env.getRequiredProperty("artemis.connection.attempts.reconnect", Integer.class));
artemisConnectionFactory.setRetryInterval(env.getRequiredProperty("artemis.retry.interval.millis", Long.class));
artemisConnectionFactory
.setRetryIntervalMultiplier(env.getRequiredProperty("artemis.retry.interval.multiplier", Double.class));
artemisConnectionFactory.setBlockOnAcknowledge(true);
artemisConnectionFactory.setBlockOnDurableSend(true);
artemisConnectionFactory.setCacheDestinations(true);
artemisConnectionFactory.setConsumerWindowSize(0);
artemisConnectionFactory.setMinLargeMessageSize(1024 * 1024);
CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory(artemisConnectionFactory);
cachingConnectionFactory
.setSessionCacheSize(env.getRequiredProperty("artemis.session.cache.size", Integer.class));
cachingConnectionFactory.setReconnectOnException(true);
return cachingConnectionFactory;
}
@Bean
public DefaultJmsListenerContainerFactory artemisContainerFactory(ConnectionFactory artemisConnectionFactory,
JmsTransactionManager artemisJmsTransactionManager,
MappingJackson2MessageConverter mappingJackson2MessageConverter) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setCacheLevel(DefaultMessageListenerContainer.CACHE_CONSUMER);
factory.setConnectionFactory(artemisConnectionFactory);
factory.setDestinationResolver(new DynamicDestinationResolver());
factory.setMessageConverter(mappingJackson2MessageConverter);
factory.setSubscriptionDurable(Boolean.TRUE);
factory.setSubscriptionShared(Boolean.TRUE);
factory.setSessionAcknowledgeMode(Session.SESSION_TRANSACTED);
factory.setSessionTransacted(Boolean.TRUE);
factory.setTransactionManager(artemisJmsTransactionManager);
return factory;
}
private TransportConfiguration[] createTransportConfigurations() {
String connectorFactoryFqcn = NettyConnectorFactory.class.getName();
Map<String, Object> primaryTransportParameters = new HashMap<>(2, 1F);
String primaryHostname = env.getRequiredProperty("artemis.primary.hostname");
Integer primaryPort = env.getRequiredProperty("artemis.primary.port", Integer.class);
primaryTransportParameters.put("host", primaryHostname);
primaryTransportParameters.put("port", primaryPort);
return new TransportConfiguration[] {
new TransportConfiguration(connectorFactoryFqcn, primaryTransportParameters),
new TransportConfiguration(connectorFactoryFqcn, backupTransportParameters) };
}
}
我的 pom 使用 2.10.0 版的 Artemis。
我该如何解决?
解决方案
JMS 2.0 规范向后兼容 JMS 1.1,因此请确保您的类路径中只有 JMS 2 规范。我的预感是 Spring 代码中的反射调用变得一团糟,因为它们使用的是 JMS 1.1 规范类而不是正确的 JMS 2 规范类。
推荐阅读
- kubernetes - 调用什么 API 端点来获取 Kubernetes pod 或服务的 yaml?
- azure-devops - 如何在 azure devops 管道中实现两级审批
- nestjs - 相互注入网关和服务/循环依赖
- python - 如何将 href 抓取到 Pandas 数据框中?
- python - Zip 加载后文件丢失
- python - 尝试搜索 EPG XML 数据
- python - 使用 django 创建一个简单的表单并搜索 SQL 数据库
- python - 有没有一种方法可以返回一个数组的索引,从而在没有 for 循环的情况下最小化多个数组的函数的输出?
- android - JetPack Compose 禁用 BottomSheet 外部触摸
- delegates - UE4动态委托ExcuteIfBound不执行我的功能