天天看點

「幹貨」Spring Cloud 中的三種服務調用方式,你了解多少呢?

作者:網際網路架構小馬哥
「幹貨」Spring Cloud 中的三種服務調用方式,你了解多少呢?

本文主要介紹SpringCloud中三種服務調用方式:

  • Spring DiscoveryClient
  • 支援Ribbon的RestTemplate
  • Feign用戶端

搭建服務測試環境

測試中,服務發現層采用Netflix的Eureka搭建。

主要步驟如下:

1.引入Eureka所需依賴

<!--eureka服務端-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
<!--用戶端-->
<dependency>
 <groupId>org.springframework.cloud</groupId>
 <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
           

2.修改配置檔案

服務端:

eureka:
 instance:
  hostname: eureka9001.com #eureka服務端的執行個體名稱
  instance-id: eureka9001
client:
  register-with-eureka: false #false表示不向注冊中心注冊自己
  fetch-registry: false # #false 表示自己就是注冊中心,職責就是維護服務執行個體,并不需要去檢索服務
  service-url:
  defaulteZone: http://127.0.0.1:9001
           

用戶端1:

server:
  port: 8002
spring:
  application:
    name: licensingservice
eureka:
  instance:
    instance-id: licensing-service-8002
    prefer-ip-address: true
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://127.0.0.1:9001/eureka/,
           

用戶端2:

server:
 port: 8002
spring:
 application:
   name: licensingservice
eureka:
 instance:
   instance-id: licensing-service-8002
   prefer-ip-address: true
 client:
   register-with-eureka: true
   fetch-registry: true
   service-url:
     defaultZone: http://127.0.0.1:9001/eureka/,    
           

一組微服務的不同執行個體采服務名相同,不同的執行個體Id區分,分别對應,spring.application.name 和eureka.instance.instance-id。

3.啟動服務

服務端:

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

用戶端:

@SpringBootApplication
@RefreshScope
@EnableEurekaClient
public class LicenseApplication_8002 {
    public static void main(String[] args) {
        SpringApplication.run(LicenseApplication_8002.class, args);
    }
}
           

4.測試

進入到Eureka服務端位址,我這是127.0.0.1:9001,可以檢視注冊到注冊中心的服務。

如圖:

「幹貨」Spring Cloud 中的三種服務調用方式,你了解多少呢?
注意事項:Eureka通過三次心跳檢測均通過,服務才會成功注冊到注冊中心,預設每次間隔10s,及初次啟動服務需等待30s才能在Eureka中看到注冊服務。

消費者搭建

1.Discover Client方式

微服務中服務既是消費者也可以是調用者,是以消費者配置和上面服務配置大體一緻,依賴及配置參考上面服務端搭建方式。啟動主類添加EnableEurekaClient注釋:

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

核心配置類:

@Component
public class ConsumerDiscoveryClient {

  @Autowired
  private DiscoveryClient discoveryClient;

  public ServiceInstance getServiceInstance() {
    List<ServiceInstance> serviceInstances = discoveryClient.getInstances("licensingservice");
    if (serviceInstances.size() == 0) {
      return null;
    }
    return serviceInstances.get(0);
  }

  public String getUrl(String url) {
    ServiceInstance serviceInstance=this.getServiceInstance();
    if (serviceInstance==null)
      throw new RuntimeException("404 ,NOT FOUND");
    String urlR=String.format(url,serviceInstance.getUri().toString());
    return urlR;
  }
}
           

通過DiscoveryClient從Eureka中擷取licensingservice服務的執行個體數組,并傳回第一個執行個體。

測試Controller

@RestController
@RequestMapping("test")
public class TestController {
  //注意必須new,否則會被ribbon攔截器攔截,改變URL行為
  private RestTemplate restTemplate=new RestTemplate();
  @Autowired
  private ConsumerDiscoveryClient consumerDiscoveryClient;
  @RequestMapping("/getAllEmp")
  public List<Emp> getAllLicense(){
    String url=consumerDiscoveryClient.getUrl("%s/test/getAllEmp");
    return restTemplate.getForObject(url,List.class);
  }
}
           

測試:

  • 調試資訊
「幹貨」Spring Cloud 中的三種服務調用方式,你了解多少呢?

從該圖可以直覺看到licensingservice,擁有兩個服務執行個體,并可以檢視執行個體資訊。

  • 頁面傳回資訊
「幹貨」Spring Cloud 中的三種服務調用方式,你了解多少呢?

成功查詢到資料庫存儲資訊。

2.Ribbon功能的Spring RestTemplate方式

依賴同上。

核心配置類:

//指明負載均衡算法
@Bean
public IRule iRule() {
  return new RoundRobinRule();
}

@Bean
@LoadBalanced //告訴Spring建立一個支援Ribbon負載均衡的RestTemplate
public RestTemplate restTemplate() {
  return new RestTemplate();
}
           

設定負載均衡方式為輪詢方式。

測試類:

@RestController
@RequestMapping("rest")
public class ConsumerRestController {

    @Autowired
    private RestTemplate restTemplate;
    private final static String SERVICE_URL_PREFIX = "http://LICENSINGSERVICE";

    @RequestMapping("/getById")
    public Emp getById(Long id) {
        MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<String, Object>();
        paramMap.add("id", id);
        return restTemplate.postForObject(SERVICE_URL_PREFIX + "/test/getById", paramMap, Emp.class);
    }
}
           

測試結果:

  • 第一次:
「幹貨」Spring Cloud 中的三種服務調用方式,你了解多少呢?
  • 第二次:
「幹貨」Spring Cloud 中的三種服務調用方式,你了解多少呢?
  • 第三次:
「幹貨」Spring Cloud 中的三種服務調用方式,你了解多少呢?

因為采用輪詢負載均衡方式分别調用不同服務執行個體,未差別,将name做出了一定更改。

以上兩種方式對比,Ribbon方式是對第一種方式的封裝且内置不同的負載算法,支援自定義。使用更加簡單,但此兩次均需編寫RestTemplate的請求方法,較為繁瑣且容易出錯,第三種方式Feign用戶端則極大地降低了開發難度和提升速度。

3.feign用戶端方式

引入依賴:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
           

主要代碼:

@FeignClient(value = "LICENSINGSERVICE",fallbackFactory = ServiceImp.class)
public interface ServiceInterface {

  @RequestMapping("/test/getById")
  Emp getById(@RequestParam("id") Long id);

  @RequestMapping("/test/getLicenseById")
  License getLicenseById(@RequestParam("id") Long id);

  @RequestMapping("/test/getAllEmp")
  List<Emp> getAllLicense();
}
@Component
public class ServiceImp implements FallbackFactory<ServiceInterface> {

    @Override
    public ServiceInterface create(Throwable throwable) {
        return new ServiceInterface() {
            @Override
            public Emp getById(Long id) {
                Emp emp = new Emp();
                emp.setName("i am feign fallback create");
                return emp;
            }

            @Override
            public License getLicenseById(Long id) {
                return null;
            }

            @Override
            public List<Emp> getAllLicense() {
                return null;
            }
        };
    }
}
           

采用接口模式開發,通過注解指明服務名以及後備方法,在服務表現不佳時,友善傳回預設的結果,而不是一個不友好的錯誤。

主啟動類:

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

測試類:

@RestController
@RequestMapping("rest")
public class ConsumerRestController {
  @Autowired
  private ServiceInterface serviceInterface;

  @Autowired
  private RestTemplate restTemplate;
  @RequestMapping("/getById")
  public Emp getById(Long id) {
    return serviceInterface.getById(id);
  }
}
           

測試結果:

  • 正常測試:
「幹貨」Spring Cloud 中的三種服務調用方式,你了解多少呢?
  • 關閉兩個服務執行個體,模拟服務執行個體死亡:
「幹貨」Spring Cloud 中的三種服務調用方式,你了解多少呢?

Feign除了能簡化服務調用,也可以實作當調用的服務失敗時,友好地回報資訊。

此三種調用方式,由低至上,從不同層次實作了SpringCloud中的微服務互相調用。

原文連結:https://mp.weixin.qq.com/s/6Gab53whouyeoaw1nXBdlw