我想知道是否有人可以提供帮助。我的 10 岁首发是我对 JMS 和一般消息传递知之甚少(几乎一无所知) - 所以请与我一起轻松回答/评论 :)
鉴于这对我来说是一个学习练习,我正在尝试组合一个非常基本的 Spring JMS 配置,然后编写一些集成测试来帮助我理解它是如何工作的。
这是我当前的 Spring 上下文配置及其 JMS 组件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jms="http://www.springframework.org/schema/jms"
xmlns:amq="http://activemq.apache.org/schema/core"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms.xsd
http://activemq.apache.org/schema/core
http://activemq.apache.org/schema/core/activemq-core.xsd">
<bean class="com.lv.gi.jmstest.ApplicationContextProvider" />
<!-- Embedded ActiveMQ Broker -->
<amq:broker id="broker" useJmx="false" persistent="false">
<amq:transportConnectors>
<amq:transportConnector uri="tcp://localhost:0" />
</amq:transportConnectors>
</amq:broker>
<!-- ActiveMQ Destination -->
<amq:queue id="destination" physicalName="myQueueName" />
<!-- JMS ConnectionFactory to use, configuring the embedded broker using XML -->
<amq:connectionFactory id="jmsFactory" brokerURL="vm://localhost" />
<!-- JMS Producer Configuration -->
<bean id="jmsProducerConnectionFactory"
class="org.springframework.jms.connection.SingleConnectionFactory"
depends-on="broker"
p:targetConnectionFactory-ref="jmsFactory" />
<bean id="jmsProducerTemplate" class="org.springframework.jms.core.JmsTemplate"
p:connectionFactory-ref="jmsProducerConnectionFactory"
p:defaultDestination-ref="destination" />
<bean class="com.lv.gi.jmstest.JmsMessageProducer">
<constructor-arg index="0" ref="jmsProducerTemplate" />
</bean>
<!-- JMS Consumer Configuration -->
<bean id="jmsConsumerConnectionFactory"
class="org.springframework.jms.connection.SingleConnectionFactory"
depends-on="broker"
p:targetConnectionFactory-ref="jmsFactory" />
<jms:listener-container container-type="default"
connection-factory="jmsConsumerConnectionFactory"
acknowledge="auto">
<jms:listener destination="myQueueName" ref="jmsMessageListener" />
</jms:listener-container>
<bean id="jmsMessageListener" class="com.lv.gi.jmstest.JmsMessageListener" />
</beans>
我的 JmsMessageProducer 类有一个 postMessage 方法,如下所示:
public void postMessage(final String message) {
template.send(new MessageCreator() {
@Override
public Message createMessage(final Session session) throws JMSException {
final TextMessage textMessage = session.createTextMessage(message);
LOGGER.info("Sending message: " + message);
return textMessage;
}
});
}
而我的 JmsMessageListener(实现 MessageListener)有一个 onMessage 方法如下:
public void onMessage(final Message message) {
try {
if (message instanceof TextMessage) {
final TextMessage tm = (TextMessage)message;
final String msg = tm.getText();
LOGGER.info("Received message '{}'", msg);
}
} catch (final JMSException e) {
LOGGER.error(e.getMessage(), e);
}
}
在我的测试类中,我可以启动 Spring 上下文,获取 JmsMessageProducer bean,然后调用 postMessage;我按预期在控制台上看到了消息:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:/com/lv/gi/jmstest/JmsMessageListenerTest-context.xml" })
public class TestJms {
private JmsMessageProducer jmsMessageProducer;
@Before
public void setup() {
jmsMessageProducer = ApplicationContextProvider.getApplicationContext().getBean(JmsMessageProducer.class);
}
@Test
public void doStuff() throws InterruptedException {
jmsMessageProducer.postMessage("message 1");
}
}
虽然这可行,但它并不是一个真正的测试,因为除了我直观地看到控制台上收到的消息之外,我无法断言消息已收到。
我们使用 mockito,所以我想知道在我的测试中是否有一种方法可以用 mock 替换 MessageListener bean,然后对其调用 verify。我想我可以通过为这些测试提供不同的 Spring 上下文文件来做到这一点,但这可能不适用于我的下一个需求......
我所有这一切的最终目标是创建一个主题,我的消息生产者可以将消息发送到队列中,多个 MessageListener 中的 1 个将从队列中读取消息,当所有注册的侦听器都读取了消息时,消息从队列中删除。(我认为主题是正确的术语!)
为了证明这个系统可以工作,我想要一个可以启动 Spring 上下文的测试。我想做的第一件事是用 3 个都连接到同一个目的地的模拟替换侦听器,这样我就可以在每个模拟上使用验证。我会发布一条消息,然后验证是否已收到每个模拟。然后我想删除/禁用 2 个侦听器,调用 postMessage,并验证在剩下的一个模拟侦听器上调用了 onMessage 方法。然后也许等待一段时间,重新建立 2 个模拟,并验证它们的 onMessage 方法是否被调用。最后,检查消息不再在队列中(由于 3 个注册的侦听器都收到了消息)
考虑到上述情况,我认为我要做的是在运行时针对目标注册和取消注册(或禁用)侦听器,如果我能做到这一点,那么我可以注册模拟。
唷!,这很复杂!,但我希望这对我想要做什么有意义?
关于如何实现这一目标的任何指示?提前谢谢了,
弥敦道