java.util.NoSuchElementException при попытке отправить сообщения с RabbitMQ и Spring - PullRequest
0 голосов
/ 05 июня 2018

Я создаю сервис, который отправляет объекты электронной почты через RabbitMQ.Уже работает другая служба, которая принимает объекты и отправляет пользователям реальные письма.

Я получаю следующее исключение, когда запускаю свои тесты во время установки, когда Spring пытается запустить приложение spring:

java.util.NoSuchElementException
at java.util.LinkedHashMap$LinkedHashIterator.nextNode(LinkedHashMap.java:721)
at java.util.LinkedHashMap$LinkedKeyIterator.next(LinkedHashMap.java:742)
at java.util.Collections$UnmodifiableCollection$1.next(Collections.java:1042)
at org.springframework.amqp.rabbit.core.RabbitAdmin.initialize(RabbitAdmin.java:438)
at org.springframework.amqp.rabbit.core.RabbitAdmin.lambda$afterPropertiesSet$9(RabbitAdmin.java:402)
at org.springframework.amqp.rabbit.connection.CompositeConnectionListener.onCreate(CompositeConnectionListener.java:36)
at org.springframework.amqp.rabbit.connection.CachingConnectionFactory.createConnection(CachingConnectionFactory.java:566)
at org.springframework.amqp.rabbit.core.RabbitTemplate.doExecute(RabbitTemplate.java:1773)
at org.springframework.amqp.rabbit.core.RabbitTemplate.execute(RabbitTemplate.java:1748)
at org.springframework.amqp.rabbit.core.RabbitTemplate.execute(RabbitTemplate.java:1729)
at org.springframework.amqp.rabbit.core.RabbitAdmin.declareQueue(RabbitAdmin.java:219)
at it.com.my.app.mgmt.user.EmailSenderIT.setup(EmailSenderIT.java:45)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

Это отправитель почты:

@Slf4j
@Component
public class QueueEmailSender implements EmailSender {

private final AmqpTemplate mqTemplate;
private final AmqpAdmin mqAdmin;
private final String queueName;
private final String exchangeName;


@Autowired
public QueueEmailSender(AmqpTemplate mqTemplate, AmqpAdmin admin,
                        @Value("${message-queue.exchanges.emailMessageExchangeName}") String exchange,
                        @Value("${message-queue.names.emailMessageQueueName}") String queue){
    this.mqTemplate = mqTemplate;
    this.mqAdmin = admin;
    this.exchangeName = exchange;
    this.queueName = queue;
    createExchangeAndQueue();
}


@Override
public void send(EmailRequestDto email){
    try {
        log.info("sending mail with params:" + email.getReplyTo());
        sendMessage(email);
    } catch (Exception e) {
        log.error("can't send email to queue. message was {}", email, e);
    }
}

private void sendMessage(Object email) {
    mqTemplate.convertAndSend(exchangeName, queueName, email);
}

private void createExchangeAndQueue() {
    Exchange exchange = new DirectExchange(exchangeName, true, false);
    Queue queue = new Queue(queueName, true, false, false);
    System.out.println("Declaring exchange with rabbit admin");
    mqAdmin.declareExchange(exchange);
    mqAdmin.declareQueue(queue);
    mqAdmin.declareBinding(new Binding(queueName, Binding.DestinationType.QUEUE, exchangeName, queueName, null));
}
}

это тест:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class EmailSenderIT {

@Autowired
private RabbitTemplate rabbitTemplate;

@Autowired
private RabbitAdmin rabbitAdmin;

@Autowired
private EmailSender emailSender;

private String queueName = "email.message.test";

private String exchangeName = "email.exchange.test";

@Before
public void setup() {
    Queue queue = new Queue(queueName, true,
            false, false);
    Exchange exchange = new DirectExchange(exchangeName, true, false);
    rabbitAdmin.declareQueue(queue);
    rabbitAdmin.declareExchange(exchange);
    rabbitAdmin.declareBinding(new Binding(queueName, Binding.DestinationType.QUEUE, exchangeName, queueName, null));

    rabbitAdmin.purgeQueue(queueName, false);
}

@Test
public void queueMessageSentWhenWhenRequestIsMade() {
    String address = "a@g.com";
    emailSender.send(EmailRequestDto.builder().from(ContactInfoDto.builder().address(address).build()).build());

    EmailRequestDto msg = rabbitTemplate.receiveAndConvert(queueName, 2000L, new ParameterizedTypeReference<EmailRequestDto>() { });
    Assert.assertEquals(address, msg.getFrom().getAddress());
}

это класс, который определяет компоненты:

@Configuration
public class MQConfig {

@Bean
public AbstractConnectionFactory connectionFactory(MQConfigParams configurationParams){
    AbstractConnectionFactory connectionFactory = new CachingConnectionFactory();
    connectionFactory.setVirtualHost(configurationParams.getVirtualHost());
    connectionFactory.setPassword(configurationParams.getPassword());
    connectionFactory.setUsername(configurationParams.getUserName());
    connectionFactory.setHost(configurationParams.getHost());
    System.out.println("creating rabbit connection factory!");
    return connectionFactory;
}

@Bean
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(AbstractConnectionFactory connectionFactory) {
    SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
    factory.setConnectionFactory(connectionFactory);
    factory.setDefaultRequeueRejected(false);
    return factory;
}

@Bean
public RabbitTemplate rabbitTemplate(AbstractConnectionFactory connectionFactory){
    System.out.println("creating rabbit template!");
    RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
    rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
    return rabbitTemplate;
}

@Bean
public AmqpAdmin rabbitAdmin(AbstractConnectionFactory connectionFactory) {
    System.out.println("creating rabbit admin!");
    return new RabbitAdmin(connectionFactory);
}

}

Я использую Spring 1.5.9.RELEASE и rabbit и amqp 2.0.1.RELEASE

Еще одна вещь: если я запускаю приложение локально, оно может без проблем запускаться, и если я инициализирую RabbitAdmin и RabbitTemplate без использования Spring в конструкторе QueueEmailSender тест пройден.

Помощь будет очень признательна!

Ответы [ 2 ]

0 голосов
/ 11 июня 2018

Наконец-то нашли решение!Это ошибка в реализации RabbitAdmin, подробности в этом выпуске

Проблема решена, поэтому по мере выполнения рекомендации я добавил флаг в свой код в MQConfig:

@Bean
public AmqpAdmin rabbitAdmin(AbstractConnectionFactory connectionFactory) {
    RabbitAdmin admin = new RabbitAdmin(connectionFactory);
    admin.setDeclareCollections(false);
    return admin;
}

Я также изменил версию, которую я использую:

compile group: 'org.springframework.amqp', name: 'spring-rabbit', version: '2.0.3.RELEASE'

compile group: 'org.springframework.amqp', name: 'spring-amqp', version: '2.0.3.RELEASE'

0 голосов
/ 05 июня 2018

Edit - не NPE, мой плохой взгляд на исходный код Spring, но мне любопытно, какая строка - EmailSenderIt.java:45

Похоже, что вы

rabbitAdmin.declareBinding(new Binding(queueName, Binding.DestinationType.QUEUE, exchangeName, queueName, null));

выдаст NPE, так как ваши аргументы (https://docs.spring.io/spring-amqp/api/org/springframework/amqp/core/Binding.html#getArguments--) равны нулю.Этот журнал должен указывать на ту же строку

"на it.com.my.app.mgmt.user.EmailSenderIT.setup (EmailSenderIT.java:45)"

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...