マイクロサービスアーキテクチャにおいて、複数のサービスを連携させて機能を実現する必要がある場合が頻繁にあります。このような状況で、サービス間の通信方法は設計の重要な要素となります。ここでは3つの代表的なアプローチを紹介します。
一、RestTemplateによる通信
@Bean
public RestTemplate createRestClient() {
return new RestTemplate();
}
サービスコンシューマー(order)がサービスプロバイダー(Goods)を呼び出す例です。
@Autowired
private RestTemplate restTemplate;
@GetMapping("/placeOrder/{pid}/{quantity}")
public Order processOrder(@PathVariable("pid") Integer id, @PathVariable("quantity") Integer qty) {
log.info("注文処理開始: 商品情報取得({})", id);
Goods product = restTemplate.getForObject("http://localhost:9002/product/detail/" + id, Goods.class);
log.info("取得完了: {}", JSON.toJSONString(product));
log.info("注文作成中");
Order order = new Order();
order.setUserId(1);
order.setUsername("テストユーザー");
order.setProductId(product.getId());
order.setProductName(product.getName());
order.setQuantity(qty);
orderService.save(order);
log.info("注文完了");
return order;
}
コード表示この方法ではサービス間通信が可能ですが、IPアドレスやポート番号のハードコーディングが発生します。サービスの配置先が変更された場合や、複数のプロバイダーが存在する場合に柔軟性が欠如します。
サービスの自動登録・発見機能が必要となり、Nacosを導入します。
二、Nacos登録中心の導入
- 依存関係の追加
<!-- Nacosクライアント -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
- 設定ファイルの更新
spring:
cloud:
nacos:
discovery:
server-addr: 192.168.206.151:8848
- アノテーションの追加
@EnableDiscoveryClient
- コードの変更例
@Autowired
private RestTemplate restTemplate;
@Autowired
private DiscoveryClient serviceRegistry;
@GetMapping("/placeOrder2/{pid}/{quantity}")
public Order processOrder2(@PathVariable("pid") Integer id, @PathVariable("quantity") Integer qty) {
log.info("注文処理開始: 商品情報取得({})", id);
ServiceInstance instance = serviceRegistry.getInstances("product-service").get(0);
String endpoint = instance.getHost() + ":" + instance.getPort();
Goods product = restTemplate.getForObject("http://" + endpoint + "/product/detail/" + id, Goods.class);
log.info("取得完了: {}", JSON.toJSONString(product));
log.info("注文作成中");
Order order = new Order();
order.setUserId(1);
order.setUsername("テストユーザー");
order.setProductId(product.getId());
order.setProductName(product.getName());
order.setQuantity(qty);
orderService.save(order);
log.info("注文完了");
return order;
}
DiscoveryClientはサービスの登録情報を管理し、動的にエンドポイントを取得できます。
三、Feignによるサービス呼び出し FeignはSpring Cloudが提供する宣言型のHTTPクライアントで、リモート呼び出しがローカルメソッド呼び出しのように簡潔に記述可能です。Nacos環境ではRibbonによるロードバランシングがデフォルトで動作します。
実装手順:
- 依存関係の追加
<!-- Feignクライアント -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
- 起動クラスへのアノテーション
@EnableFeignClients
- クライアントインターフェースの作成
@FeignClient("product-service")
public interface ProductApiClient {
@GetMapping("/product/detail/{id}")
Goods retrieveProduct(@PathVariable("id") Integer id);
}
- 使用例
@Autowired
private ProductApiClient productClient;
@GetMapping("/placeOrder3/{pid}/{quantity}")
public Order processOrder3(@PathVariable("pid") Integer id, @PathVariable("quantity") Integer qty) {
log.info("注文処理開始: 商品情報取得({})", id);
Goods product = productClient.retrieveProduct(id);
log.info("取得完了: {}", JSON.toJSONString(product));
log.info("注文作成中");
Order order = new Order();
order.setUserId(1);
order.setUsername("テストユーザー");
order.setProductId(product.getId());
order.setProductName(product.getName());
order.setQuantity(qty);
orderService.save(order);
log.info("注文完了");
return order;
}