[英]Spring Boot, JmsListener and SQS queues on different accounts
我正在尝试开发一个 Spring Boot(1.5) 应用程序,该应用程序需要侦听来自两个不同 AWS 帐户的 SQS 队列。 是否可以使用 JmsListener 注释创建侦听器? 我已经检查过权限是否正确,我可以使用 getQueueUrl() 获取队列 url,并使用 setQueueOwnerAWSAccountId() 设置正确的帐户 ID。
以下是我用于主帐户下的侦听器的代码。 尝试将其用于另一个帐户的队列,会出现错误
HTTPStatusCode: 400 AmazonErrorCode: AWS.SimpleQueueService.NonExistentQueue
com.amazonaws.services.sqs.model.QueueDoesNotExistException: The specified queue does not exist for this wsdl version.
队列阅读器类
@Service
public class QueueReader {
@JmsListener(destination = "queue-name")
public void messageReceived(@Payload String message) {
// message received
}
}
队列配置类
@Configuration
@EnableJms
public class QueueReaderConfig {
SQSConnectionFactory connectionFactory = SQSConnectionFactory.builder().withRegion(Region.getRegion(Regions.EU_WEST_1))
.withAWSCredentialsProvider(new DefaultAWSCredentialsProviderChain())
.build();
@Bean
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() {
DefaultJmsListenerContainerFactory factory =
new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(this.connectionFactory);
factory.setDestinationResolver(new DynamicDestinationResolver());
factory.setConcurrency("3-10");
factory.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
return factory;
}
@Bean
public JmsTemplate defaultJmsTemplate() {
return new JmsTemplate(this.connectionFactory);
}
}
我陷入了同样的问题。 通过创建自定义DestinationResolver并将其设置在“ DefaultJmsListenerContainerFactory”和“ JmsTemplate”中,我找到了一种解决方法。
另外,在“ CustomDynamicDestinationResolver”中,按ownerAccountId查找队列。
queue = ((SQSSession) session).createQueue(queueName, ownerAccountId);
通过使用连接工厂来监听队列。
@JmsListener(destination = "MyQueue", containerFactory = "customJmsListenerContainerFactory")
public void process(String message) throws IOException {
有点晚了,但是,我希望这可以帮助像我这样的人寻求解决方案。
谢谢,
阿克沙伊
import com.amazon.sqs.javamessaging.ProviderConfiguration;
import com.amazon.sqs.javamessaging.SQSConnectionFactory;
import com.amazon.sqs.javamessaging.SQSSession;
import com.amazonaws.auth.DefaultAWSCredentialsProviderChain;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.sqs.AmazonSQSClientBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.support.destination.DestinationResolver;
import org.springframework.util.Assert;
import javax.jms.*;
@Configuration
public class CustomJmsConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(CustomJmsConfig.class);
@Value("${copies.processor.concurrency:5}")
private String concurrency;
@Value("${owner.account.id:1234}")
private String ownerAccountId;
SQSConnectionFactory customConnectionFactory =
new SQSConnectionFactory(
new ProviderConfiguration(),
AmazonSQSClientBuilder.standard().withRegion(Regions.EU_CENTRAL_1).withCredentials(new DefaultAWSCredentialsProviderChain())
);
@Bean
public DefaultJmsListenerContainerFactory customJmsListenerContainerFactory() {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(this.customConnectionFactory);
factory.setDestinationResolver(new CustomDynamicDestinationResolver(ownerAccountId));
factory.setConcurrency(concurrency);
factory.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
return factory;
}
@Bean
public JmsTemplate customJmsTemplate() {
JmsTemplate jmsTemplate = new JmsTemplate(this.customConnectionFactory);
jmsTemplate.setDestinationResolver(new CustomDynamicDestinationResolver(ownerAccountId));
return jmsTemplate;
}
public static class CustomDynamicDestinationResolver implements DestinationResolver {
private String ownerAccountId;
public CustomDynamicDestinationResolver(String ownerAccountId) {
this.ownerAccountId = ownerAccountId;
}
@Override
public Destination resolveDestinationName(Session session, String destinationName, boolean pubSubDomain) throws JMSException {
Assert.notNull(session, "Session must not be null");
Assert.notNull(destinationName, "Destination name must not be null");
if (pubSubDomain) {
return resolveTopic(session, destinationName);
} else {
return resolveQueue(session, destinationName);
}
}
protected Topic resolveTopic(Session session, String topicName) throws JMSException {
return session.createTopic(topicName);
}
protected Queue resolveQueue(Session session, String queueName) throws JMSException {
Queue queue;
LOGGER.info("Getting destination for libraryOwnerAccountId: {}, queueName: {}", libraryOwnerAccountId, queueName);
if (libraryOwnerAccountId != null && session instanceof SQSSession) {
queue = ((SQSSession) session).createQueue(queueName, ownerAccountId);
} else {
queue = session.createQueue(queueName);
}
return queue;
}
}
}
我的解决方案基于 Akshay 的回应。 我也在使用自定义DestinationResolver
。 但是我的实现不需要固定的ownerAccountId
:
public class SqsDynamicDestinationResolver extends DynamicDestinationResolver {
@Override
protected Queue resolveQueue(Session session, String queueName) throws JMSException {
if (session instanceof SQSSession) {
SQSSession sqsSession = (SQSSession) session;
String[] parts = queueName.split(":");
if (parts.length == 2) {
return sqsSession.createQueue(parts[1], parts[0]);
}
}
return super.resolveQueue(session, queueName);
}
然后在JmsTemplate
和DefaultJmsListenerContainerFactory
设置解析器。
您可以简单地将队列名称指定为"whatever_queue_name"
或使用冒号分隔的所有者帐户 ID,例如"0000216587:whatever_queue_name"
。
请注意,如果ownerAccountId
来自不同地区,则此解决方案将不起作用! 在这种情况下,您将需要单独的配置。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.