Spring Cloud Alibaba教程——Nacos微服務調用

教程倉庫:github Spring-Cloud-Alibaba-Learning


教程索引頁:index Spring-Cloud-Alibaba-Learning



源碼地址

本篇內容的項目地址爲:微服務調用

目標

  1. 可以根據服務名獲取到該服務的節點列表
  2. 可以獲取到在服務註冊中心註冊成功的所有服務名
  3. 完成跨服務的遠程調用

準備工作

保證Nacos在啓動狀態,且確保兩個服務(service-a和service-b)每次啓動時都能成功註冊到Nacos上


流程

一、根據服務名獲取節點列表

我們在service-a中寫一個控制器,在裏面寫一個接口,獲取服務名爲service-b的節點列表。

  1. 我們需要使用SpringCloud爲我們提供的一個組件DiscoveryClient

        //由SpringCloud提供的組件,和Nacos解耦
        //也就是說 如果我們不使用Nacos而是其他的服務發現組件,依然可以使用DiscoveryClient
    	@Autowired
        private DiscoveryClient discoveryClient;
    
  2. 接下來寫一個接口來獲取服務名爲service-b的節點實例

        /**
         * 測試服務發現
         * 獲取服務名爲service-b的所有服務節點實例
         * @return serviceInstanceList
         */    
    	@GetMapping("testInstances")
        public List<ServiceInstance> getInstances(){
             return discoveryClient.getInstances("service-b");
        }
    

接下來做三次測試

  1. 啓動service-a,不啓動service-b,測試接口testInstances,得到返回值如下:

    []
    
  2. 啓動service-a,啓動一個service-b實例,測試接口testInstances,得到返回值如下:

    [
      {
        "serviceId": "service-b",
        "host": "192.168.2.101",
        "port": 8182,
        "secure": false,
        "metadata": {
          "nacos.instanceId": "192.168.2.101#8182#DEFAULT#DEFAULT_GROUP@@service-b",
          "nacos.weight": "1.0",
          "nacos.cluster": "DEFAULT",
          "nacos.healthy": "true",
          "preserved.register.source": "SPRING_CLOUD"
        },
        "uri": "http://192.168.2.101:8182"
      }
    ]
    
  3. 啓動service-a,啓動兩個service-b實例,測試接口testInstances,得到返回值如下:

    [
      {
        "serviceId": "service-b",
        "host": "192.168.2.101",
        "port": 8182,
        "secure": false,
        "metadata": {
          "nacos.instanceId": "192.168.2.101#8182#DEFAULT#DEFAULT_GROUP@@service-b",
          "nacos.weight": "1.0",
          "nacos.cluster": "DEFAULT",
          "nacos.healthy": "true",
          "preserved.register.source": "SPRING_CLOUD"
        },
        "uri": "http://192.168.2.101:8182"
      },
      {
        "serviceId": "service-b",
        "host": "192.168.2.101",
        "port": 8183,
        "secure": false,
        "metadata": {
          "nacos.instanceId": "192.168.2.101#8183#DEFAULT#DEFAULT_GROUP@@service-b",
          "nacos.weight": "1.0",
          "nacos.cluster": "DEFAULT",
          "nacos.healthy": "true",
          "preserved.register.source": "SPRING_CLOUD"
        },
        "uri": "http://192.168.2.101:8183"
      }
    ]
    

至此,testInstances接口測試成功。我們可以看到確實是根據服務名獲取到了全部的節點列表。

二、根據服務名獲取節點列表

在這裏我們調用DiscoveryClient的另一個API:discoveryClient.getServices()

    /**
     * 測試服務發現
     * 獲取服務名列表
     * @return serviceNamesList
     */
    @GetMapping("testServices")
    public List<String> getServiceNames(){
        return discoveryClient.getServices();
    }

然後啓動一下,會看到我們當前啓動的服務名列表:

[
  "service-a",
  "service-b"
]

三、完成跨服務的遠程調用

在這裏我們藉助RestTemplate來完成一個簡單的遠程調用。

  1. service-b中添加一個可供遠程調用的服務

    @RestController
    public class TestController {
        @GetMapping("test/{argue}")
        public String test(@PathVariable("argue") String argue){
            return "this is service-b, argue = " + argue;
        }
    }
    
  2. service-a中添加RestTemplate組件。在本例中直接加在了Application啓動類中,當然我們也可以單獨寫一個Configuration

    	@Bean
    	public RestTemplate restTemplate(){
    		return new RestTemplate();
    	}
    
  3. 編寫一個接口,裏面調用遠程服務,編碼思路如下:

    1. 藉助discoveryClient獲取到服務名爲service-b的所有運行中實例列表instances
    2. 取出instances中的第一個實例的uri,並追加*/test/{argue}字符串,得到targetUrl*,以定位到service-b中的一項具體服務
    3. targetUrl填入參數,併發起get請求(restTemplate.getForObject)
    4. 返回遠程調用結果
    @RestController
    @Slf4j
    public class RemotingController {
    
        @Autowired
        private RestTemplate restTemplate;
    
        @Autowired
        private DiscoveryClient discoveryClient;
    
        @GetMapping("remote")
        public String remote(){
            List<ServiceInstance> instances = discoveryClient.getInstances("service-b");
    
            //找到instances中第一個實例的地址(uri)
            String targetUrl = instances.stream()
                    .map(instance -> instance.getUri().toString() + "/test/{argue}")
                    .findFirst()
                    .orElseThrow(() -> new IllegalArgumentException("當前沒有實例"));
    
            log.info("請求的目標地址:{}",targetUrl);
    
            //調用service-b的服務
            //用http get請求,並且返回對象
            return restTemplate.getForObject(
                    targetUrl,
                    String.class,
                    "argue from service-a"
            );
    
        }
    
    }
    

測試一下接口,結果如下:

this is service-b, argue = argue from service-a


上篇:Spring Cloud Alibaba教程——Nacos(一)集成Nacos
下篇:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章