本样例程序使用rabbitmq消息队列模拟了一个简单的股票交易系统,它基本上等同于Spring AMQP的一个样例程序stocks,只是做了一些增强性的配置以使其能够在Cloud Foundry平台之上良好运行。
交易信息的发送由 java/org/springframework/amqp/rabbit/stocks/gateway/RabbitStockServiceGateway.java 的 send() 方法完成:
程序默认的实时报价更新频率为5秒,可通过以下方式更改:
本程序repository:https://github.com/SpringSource/cloudfoundry-samples/tree/master/stocks
也可以参考其原版的Spring AMQP stocks样例:http://github.com/SpringSource/spring-amqp-samples
本程序对原版样例程序的增强之处在于,引入了Cloud Foundry平台的运行时环境变量,程序能够检测到运行时环境是在本地还是云平台,另外还使用到了Redis存储服务。
首先来看一下这个应用程序的UI。构建好程序并push到Cloud Foundry之后(需要绑定rabbitmq和redis两种云服务),在浏览器中访问应用程序,可看到类似以下的界面:
页面下方实时更新当前每支股票的交易价格。在上方股票交易区输入交易数目及股票代号后单击"Send",可显示详细的交易信息。这就是本程序所实现的全部应用场景。
一、RabbitMQ
股票交易信息和实时报价均通过RabbitMQ消息队列发送或获取。交易信息的发送由 java/org/springframework/amqp/rabbit/stocks/gateway/RabbitStockServiceGateway.java 的 send() 方法完成:
public class RabbitStockServiceGateway extends RabbitGatewaySupport implements StockServiceGateway {
private String defaultReplyTo;
public void setDefaultReplyTo(String defaultReplyTo) {
this.defaultReplyTo = defaultReplyTo;
}
public void send(TradeRequest tradeRequest) {
getRabbitTemplate().convertAndSend(tradeRequest, new MessagePostProcessor() {
public Message postProcessMessage(Message message) throws AmqpException {
message.getMessageProperties().setReplyTo(new Address(defaultReplyTo));
try {
message.getMessageProperties().setCorrelationId(UUID.randomUUID().toString().getBytes("UTF-8"));
}
catch (UnsupportedEncodingException e) {
throw new AmqpException(e);
}
return message;
}
});
}
}
对RabbitStockServiceGateway bean进行配置,将交易信息发送到制定的rabbit队列中。见 resources/servlet-config.xml 文件:
<bean id="stockServiceGateway" class="org.springframework.amqp.rabbit.stocks.gateway.RabbitStockServiceGateway">
<property name="rabbitTemplate">
<rabbit:template connection-factory="connectionFactory" routing-key="app.stock.request"
message-converter="jsonMessageConverter" />
</property>
<property name="defaultReplyTo" value="fanout://broadcast.responses/" />
</bean>
实时报价则是通过 java / org / springframework / amqp / rabbit / stocks / gateway / RabbitMarketDataGateway.java 来模拟。之所以说是模拟,因为这里的报价是随机产生的符合正态分布的随机数,并非实际股票市场的报价。见代码:
private String randomPrice() {
return this.twoPlacesFormat.format(this.basePrice + Math.abs(random.nextGaussian()));
}
二、Redis
该应用程序的运行并未直接使用redis存储服务。这里绑定redis服务,是为了能够更改并持久化应用程序的参数配置,比如报价的刷新频率。程序默认的实时报价更新频率为5秒,可通过以下方式更改:
$ curl http://stocks.vcap.me/refresh/trigger -d quote.trigger="0 * * * * *"
这里将默认的CronTrigger配置由"0/5 * * * * *",即每5秒,更改为每分钟。
通过执行命令
$ curl http://stocks.vcap.me/env
或在浏览器中访问地址 http://stocks.vcap.me/env ,可以看到环境变量 env 已经更改成功:
…… ,"env":{"quote.trigger":"0 * * * * *"}}
env 变量被持久化存储于Redis中。