Я создаю сервис, который отправляет объекты электронной почты через 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
тест пройден.
Помощь будет очень признательна!