Spring Cloud 服务通信

Spring Cloud 服务通信

  • 同步通信:

    • dobbo 通过 RPC 远程调用。
    • spring cloud 通过 REST 接口调用。
  • 异步通信:

    • 通过消息对列,如:RabbitMQ,Kafka,ActiveM 等。

本文主要介绍 Spring Cloud 使用 RestTemplate / OpenFeign 进行 REST 接口调用。

RestTemplate

通过 RestTemplate 进行调用

1
2
3
4
5
6
7
8
9
public ProductInfo getProductMsg(String id) {
    RestTemplate restTemplate = new RestTemplate();
    ProductInfo response = restTemplate.getForObject(
        "http://example.com/product/info",    // 远程调用地址
        ProductInfo.class,                    // response 类型
        id                                    // 需要传递的参数
    );
    return response;
}

利用 LoadBalancerClient 获取信息

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
@Autowired
private LoadBalancerClient loadBalancerClient;
public ProductInfo getProductMsg(String id) { 
    RestTemplate restTemplate = new RestTemplate();
    ServiceInstance serviceInstance = loadBalancerClient.choose("PRODUCT");

    // 利用 loadBalancerClient 通过应用名(spring.application.name)获取信息
    String url = String.format("http://%s:%s", serviceInstance.getHost(), serviceInstance.getPort()) + "/product/info";

    ProductInfo response = restTemplate.getForObject(url, ProductInfo.class, id);
    return response;
}

利用 LoadBalance 在 RestTemplate 中直接使用应用名称

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
class RestTemplateConfig {
    @Bean
    @LoadBalance
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

---

@Autowired
private RestTemplate restTemplate;
public ProductInfo getProductMsg(String id) {
    // 利用 @LoadBalance 可以在 RestTemplate 中使用应用名称
    ProductInfo response = restTemplate.getForObject("http://PRODUCT/product/msg", ProductInfo.class, id);
    return response;
}

OpenFeign (推荐)

引入依赖

1
2
3
4
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

添加启动注解

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import org.springframework.cloud.openfeign.EnableFeignClients;

@EnableFeignClients
@SpringBootApplication
@EnableDiscoveryClient
public class FeignApplication {
    public static void main(String[] args) {
        SpringApplication.run(FeignApplication.class, args);
    }
}

具体实现

现在有两个服务,分别为 Prodcut 和 Order 。 需求: Order 服务中,客户进行了下单操作后,调用 Product(Feign) 的进行减库存操作。

  • Product 服务中,定义远程调用端。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public class DecreaseStockInput {
    // ...
}

---

@FeignClient(name = "product")  // name: 远程服务名(Spring.application.name)
public interface ProductClient {

    @RequestMapping(value = "/product/decrease_stock")
    void decreaseStock(@RequestBody List<DecreaseStockInput> decreaseStockInputList);
}
  • Order 服务中,对 Product Client 进行调用。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
@Service
public class OrderServiceImpl implements OrderService {
    // 注入的为 Product 中的 ProductClient
    // 通过依赖的方式
    @Autowired
    private ProductClient productClient;

    public OrderDTO create(OrderDTO orderDTO) {
        // ...
        // 调用 Product 服务中的 api 进行减库存操作
        productClient.decreaseStock(decreaseStockInputList);
        // ...
    }
}