add rabbitmq rpc sample

This commit is contained in:
Xiong Neng
2018-05-17 15:11:08 +08:00
parent 66c4d7ae39
commit f8e958fa71
21 changed files with 933 additions and 0 deletions

View File

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2018 Xiong Neng
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,9 @@
## RabbitMQ实现RPC调用客户端
消息队列RabbitMQ的使用例子演示了RPC调用的客户端例子。
## 许可证
Copyright (c) 2018 Xiong Neng
基于 MIT 协议发布: <http://www.opensource.org/licenses/MIT>

View File

@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.xncoding</groupId>
<artifactId>springboot-rabbitmq-rpc-client</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>springboot-rabbitmq-rpc-client</name>
<description>集成消息队列RabbitMQ RPC调用 - 客户端</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.10.RELEASE</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<exclusions>
<exclusion>
<groupId>com.vaadin.external.google</groupId>
<artifactId>android-json</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<!--<proc>none</proc>-->
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
</project>

View File

@ -0,0 +1,12 @@
package com.xncoding.pos;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

View File

@ -0,0 +1,89 @@
package com.xncoding.pos.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.core.AnonymousQueue;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.AsyncRabbitTemplate;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.scheduling.annotation.EnableAsync;
import javax.annotation.Resource;
/**
* RabbitConfig
*
* @author XiongNeng
* @version 1.0
* @since 2018/3/1
*/
@Configuration
public class RabbitConfig {
/**
* 同步RPC队列
*/
public static final String QUEUE_SYNC_RPC = "rpc.sync";
/**
* 异步RPC队列使用临时回复队列或者使用“Direct reply-to”特性
*/
public static final String QUEUE_ASYNC_RPC = "rpc.async";
/**
* 异步RPC队列每个客户端使用不同的固定回复队列需要额外提供correlationId以关联请求和响应
*/
public static final String QUEUE_ASYNC_RPC_WITH_FIXED_REPLY = "rpc.with.fixed.reply";
@Bean
public Queue syncRPCQueue() {
return new Queue(QUEUE_SYNC_RPC);
}
@Bean
public Queue asyncRPCQueue() {
return new Queue(QUEUE_ASYNC_RPC);
}
@Bean
public Queue fixedReplyRPCQueue() {
return new Queue(QUEUE_ASYNC_RPC_WITH_FIXED_REPLY);
}
@Bean
public Queue repliesQueue() {
return new AnonymousQueue();
}
@Bean
public MessageConverter jsonMessageConverter(){
return new Jackson2JsonMessageConverter();
}
@Bean
@Primary
public SimpleMessageListenerContainer replyContainer(ConnectionFactory connectionFactory) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
container.setQueueNames(repliesQueue().getName());
return container;
}
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMessageConverter(jsonMessageConverter());
return rabbitTemplate;
}
@Bean
public AsyncRabbitTemplate asyncRabbitTemplate(RabbitTemplate template, SimpleMessageListenerContainer container) {
return new AsyncRabbitTemplate(template, container);
}
}

View File

@ -0,0 +1,29 @@
package com.xncoding.pos.model;
/**
* User
*
* @author XiongNeng
* @version 1.0
* @since 2018/5/17
*/
public class User {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}

View File

@ -0,0 +1,51 @@
package com.xncoding.pos.service;
import com.xncoding.pos.model.User;
import com.xncoding.pos.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.AsyncRabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.util.concurrent.ListenableFuture;
import java.util.concurrent.Future;
import static com.xncoding.pos.config.RabbitConfig.QUEUE_ASYNC_RPC;
import static com.xncoding.pos.config.RabbitConfig.QUEUE_ASYNC_RPC_WITH_FIXED_REPLY;
/**
* 消息发送服务
*/
@Service
public class SenderService {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
AsyncRabbitTemplate asyncRabbitTemplate;
@Autowired
AmqpTemplate amqpTemplate;
@Async
public Future<String> sendAsync(User message) {
// String result = (String) amqpTemplate.convertSendAndReceive(QUEUE_ASYNC_RPC, message, m -> {
// m.getMessageProperties().setCorrelationIdString(StringUtil.generateUUId());
// return m;
// });
String result = (String) amqpTemplate.convertSendAndReceive(QUEUE_ASYNC_RPC, message);
return new AsyncResult<>(result);
}
public Future<String> sendWithFixedReplay(User message) {
// ListenableFuture<String> future = asyncRabbitTemplate.convertSendAndReceive(QUEUE_ASYNC_RPC_WITH_FIXED_REPLY, message, m -> {
// m.getMessageProperties().setCorrelationIdString(StringUtil.generateUUId());
// return m;
// });
return asyncRabbitTemplate.convertSendAndReceive(QUEUE_ASYNC_RPC_WITH_FIXED_REPLY, message);
}
}

View File

@ -0,0 +1,16 @@
package com.xncoding.pos.util;
import java.util.UUID;
/**
* StringUtil
*
* @author XiongNeng
* @version 1.0
* @since 2018/5/17
*/
public class StringUtil {
public static String generateUUId() {
return UUID.randomUUID().toString();
}
}

View File

@ -0,0 +1,29 @@
##########################################################
################## 所有profile共有的配置 #################
##########################################################
################### spring配置 ###################
spring:
profiles:
active: dev
---
#####################################################################
######################## 开发环境profile ##########################
#####################################################################
spring:
profiles: dev
rabbitmq:
host: 119.29.12.177
port: 5672
username: guest
password: guest
logging:
level:
ROOT: INFO
com:
xncoding: DEBUG
file: D:/logs/rabbitmq-rpc-client.log

View File

@ -0,0 +1,90 @@
package com.xncoding.service;
import com.xncoding.pos.Application;
import com.xncoding.pos.model.User;
import com.xncoding.pos.service.SenderService;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
/**
* SenderServiceTest
*
* @author XiongNeng
* @version 1.0
* @since 2018/2/2
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class SenderServiceTest {
Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private SenderService senderService;
private List<User> users;
@Before
public void prepare() {
users = new ArrayList<>();
User user1 = new User();
user1.setName("用户1");
user1.setAge(19);
users.add(user1);
User user2 = new User();
user2.setName("用户2");
user2.setAge(20);
users.add(user2);
}
@Test
public void testSendAsync() throws InterruptedException, ExecutionException {
List<Future<String>> results = new ArrayList<>();
for (User user : users) {
Future<String> result = senderService.sendAsync(user);
results.add(result);
}
for (Future<String> future : results) {
String result = future.get();
if (result == null) {
Assert.fail("message will not timeout");
} else {
logger.info("tttttttttttt=" + result);
}
}
}
@Test
public void testSendWithFixedReplay() throws InterruptedException, ExecutionException{
List<Future<String>> results = new ArrayList<>();
for (User user : users) {
Future<String> result = senderService.sendWithFixedReplay(user);
results.add(result);
}
for (Future<String> future : results) {
String result = future.get();
if (result == null) {
Assert.fail("message will not timeout");
} else {
logger.info("tttttttttttt=" + result);
}
}
}
}