Лучшее место, чтобы начать это projects getting started guide
Ваш подход является правильным в общих чертах, но он то, что скелет выглядит.
Первый весенний ботинок дает вам идеальную конфигурацию файловой структуры, и если вы используете умный идеал, такой как Netbeans, то добавив плагин spring-boot, вы также получите автозаполнение в файле свойств. Поскольку весна действует немного по-разному с каждым брокером, в моих примерах я буду использовать ActiveMQ
Просто имея ActiveMQ на нашем пути сборки, Spring Boot автоматически настроит брокер ActiveMQ. Нам нужно установить пару свойств, чтобы сделать это в брокере памяти, без объединения пулов. Мы можем сделать это, установив два свойства для Spring Boot.
spring.activemq.in-memory=true
spring.activemq.pooled=false
jms.bookmgrqueue.name=book-mgr-queue #queue name
Аналогичные конфигурации могут быть выполнены и для других брокеров.
Сначала вы начинаете с установки приложения Spring. Вы должны разместить аннотацию @EnableJms
, чтобы включить поддержку Jms, а затем настроить новую очередь.
Пример
@EnableJms
@Configuration
public class JmsConfiguration {
@Autowired
private BeanFactory springContextBeanFactory;
@Bean
public DefaultJmsListenerContainerFactory containerFactory(ConnectionFactory connectionFactory) {
DefaultJmsListenerContainerFactory factory =
new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
factory.setDestinationResolver(new BeanFactoryDestinationResolver(springContextBeanFactory));
factory.setConcurrency("3-10");
return factory;
}
@Bean
public JmsTemplate jmsTemplate(ConnectionFactory connectionFactory) throws JMSException {
return new JmsTemplate(connectionFactory);
}
}
Прослушивание очереди сообщений
Слушатель компонент (BookMgrQueueListener.java) использует @JmsListener
аннотацию Spring с селекторами, чтобы читать сообщения с заданным заголовком операции.
@Component
public class BookMgrQueueListener implements Loggable{
private final BookService bookService;
@Autowired
public BookMgrQueueListener(BookService bookService) {
this.bookService = bookService;
}
@JmsListener(containerFactory = "containerFactory",
destination = "bookMgrQueueDestination",
selector = "Operation = 'Create'")
public void processCreateBookMessage(BookDTO book) throws JMSException{
bookService.createNew(book);
}
@JmsListener(containerFactory = "containerFactory",
destination = "bookMgrQueueDestination",
selector = "Operation = 'Update'")
public void processUpdateBookMessage(BookDTO book) throws JMSException{
bookService.update(book.getIsbn(), book);
}
@JmsListener(containerFactory = "containerFactory",
destination = "bookMgrQueueDestination",
selector = "Operation = 'Delete'")
public void processDeleteBookMessage(BookDTO book) throws JMSException{
bookService.delete(book.getIsbn());
}
}
Активный MQ для испытания
Для проверки конфигурации мы создаем ActiveMQ брокера в новом файле конфигурации, ActiveMqConfiguration.java.
@Configuration
public class ActiveMqConfiguration {
public static final String ADDRESS = "vm://localhost";
private BrokerService broker;
@Bean(name="bookMgrQueueDestination")
public Destination bookMgrQueueDestination(@Value("${jms.bookmgrqueue.name}") String bookMgrQueueName)
throws JMSException {
return new ActiveMQQueue(bookMgrQueueName);
}
@PostConstruct
public void startActiveMQ() throws Exception {
broker = new BrokerService();
// configure the broker
broker.setBrokerName("activemq-broker");
broker.setDataDirectory("target");
broker.addConnector(ADDRESS);
broker.setUseJmx(false);
broker.setUseShutdownHook(false);
broker.start();
}
@PreDestroy
public void stopActiveMQ() throws Exception {
broker.stop();
}
@Bean
public ConnectionFactory connectionFactory() {
return new ActiveMQConnectionFactory(ADDRESS + "?broker.persistent=false");
}
}
Мы создаем полный контекст приложения в TestCase, но мы заменяем ссылку BookService в слушателе к MockedBookService, который мы будем использовать, чтобы проверить, были ли выполнены правильные звонки.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = Application.class, loader = SpringApplicationContextLoader.class)
@WebAppConfiguration
public class BookMgrQueueListenerIntegrationTest {
@Autowired(required = false)
private JmsTemplate jmsTemplate;
@Autowired
private BookMgrQueueListener bookMgrQueueListener;
@Autowired(required = false)
@Qualifier("bookMgrQueueDestination")
private Destination bookMgrQueueDestination;
@Mock
private BookService mockBookService;
@Captor
private ArgumentCaptor<BookDTO> bookArgumentCaptor;
@Before
public void setUp(){
MockitoAnnotations.initMocks(this);
ReflectionTestUtils.setField(bookMgrQueueListener, "bookService", mockBookService);
}
/* ... tests */
}
Наконец, мы добавляем тесты для всех операций и проверяем, был ли вызван служебный уровень с правильными операциями и параметрами.
/* ... */
public class BookMgrQueueListenerIntegrationTest {
/* ... */
@Test
public void testSendCreateBookMessage(){
BookDTO book = new BookDTO("isbn", "title", "author");
jmsTemplate.convertAndSend(bookMgrQueueDestination, book, Message -> {
return OperationHeader.CREATE.applyToMessage(Message);
});
// verify
verify(mockBookService).createNew(bookArgumentCaptor.capture());
assertEquals(book.getIsbn(), bookArgumentCaptor.getValue().getIsbn());
assertEquals(book.getTitle(), bookArgumentCaptor.getValue().getTitle());
assertEquals(book.getAuthor(), bookArgumentCaptor.getValue().getAuthor());
}
@Test
public void testSendUpdateBookMessage(){
BookDTO book = new BookDTO("isbn", "title", "author");
jmsTemplate.convertAndSend(bookMgrQueueDestination, book, Message -> {
return OperationHeader.UPDATE.applyToMessage(Message);
});
// verify
verify(mockBookService).update(eq(book.getIsbn()), bookArgumentCaptor.capture());
assertEquals(book.getIsbn(), bookArgumentCaptor.getValue().getIsbn());
assertEquals(book.getTitle(),bookArgumentCaptor.getValue().getTitle());
assertEquals(book.getAuthor(),bookArgumentCaptor.getValue().getAuthor());
}
@Test
public void testSendDeleteBookMessage(){
BookDTO book = new BookDTO("isbn", "title", "author");
jmsTemplate.convertAndSend(bookMgrQueueDestination, book, Message -> {
return OperationHeader.DELETE.applyToMessage(Message);
});
// verify
verify(mockBookService).delete(book.getIsbn());
}
И мы будем рады!
Ссылки Integrate JMS queue into a Spring Application
Большое спасибо! Это было очень полезно! –
Отличный ответ и ссылки.Просто предупреждение для тех, кто хотел бы использовать Mockito.spy() в bean-компоненте с помощью аннотированного метода jmslistener: шпионаж держит его от фактического прослушивания в очереди. – Wivani