spring cloud 筆記

spring cloud

一、Eureka

1、註解:

@GetMapping("/xx"), @PostMapping, @PutMapping, @DeleteMapping, @PatchMapping;

此類註解是一個組合註解,如 @GetMapping("/xx") 等價於@RequestMapping(method = RequestMethod.GET) 。

@SpringBootApplication

是一個組合註解,整合了@Configuration 、@EnableAutoConfiguration 和 @ComponentScan三個註解。
@EnableDiscoveryClient 聲明這是一個Client,此註解也可以使用@EnableEurekaClient代替;
@EnableDiscoveryClient是spring-cloud-commons項目的註解;
@EnableEurekaClient是spring-cloud-netflix,此註解只能再Eureka中使用。
當Eureka在項目的ClassPath中時,@EnableEurekaClient和@EnableDiscoveryClient兩者使用沒有取別。(注:Spring Cloud Edgware開始,@EnableDiscoveryClient 或@EnableEurekaClient 可省略。只需加上相關依賴,並進行相應配置,即可將微服務註冊到服務發現組件上 )

@EnableCircuitBreaker

註解開啓斷路器功能

@SpringCloudApplication

包含@EnableCircuitBreaker,@SpringBootApplication,@EnableCircuitBreaker三個註解

2、Eureka 介紹

一個基於REST的服務,包含Server 和 Client 兩部分。

  1. Eureka Server:提供服務發現的能力,各個服務啓動時,會向Eureka Server 註冊自己的信息,包括IP、端口號、服務名稱等,並且會週期性(默認30秒)向Eureka Server服務中新發送心跳以續約自己的“租期”,表示自己活着。如果一定時間內(默認90秒)沒有接收到某個服務的心跳,將會註銷該服務實例。一個Eureka Server同時也是一個Eureka Client,多個Eureka Server之間通過互相複製的方式,實現服務註冊表中的數據同步。
  2. Eureka Client:用於簡化與Eureka Server交互的一個客戶端。會緩存註冊表中的信息(降低Eureka Server的壓力),即使Eureka Server掛掉,服務消費者依然可以找到服務提供者。

3、Eureka Server 配置

spring cloud 的配置文件是application.properties,還有另外一種配置方式,使用application.ym文件配置。
application.yml的配置是根據父子樹關係配置的,子節點需要在父節點下並縮進,否則會被認爲是同一級。
如:在application.properties中配置:

  1. eureka.client.register-with-eureka:表示是否將自己註冊到Eureka Server中,前面說過,Eureka Server 同時也是一個Eureka Client ,此配置表示是否作爲客戶端,默認true。
  2. eureka.client.fetch-registry:表示是否從Eureka Server獲取註冊信息,即是否緩存註冊表中的數據,默認true。
  3. erueka.client.serviceUrl.defaultZone:設置與Eureka Server交互地址,查詢服務和註冊服務都依賴的地址。多個地址使用逗號分隔,默認http://localhost:8761/erueka/。
  4. eureka.instance.lease-renewal-interval-in-seconds: 參數用於定義服務續約任務的調用間隔時間,默認爲30秒。
  5. eureka.instance.lease-expiration-­duration-in-seconds: 參數用於定義服務失效的時間,默認爲90秒

4、Eureka Server 高可用

Eureka Server可以通過多個實例之間互相註冊實現高可用部署;

Eureka 元數據:

  1. 標準元數據:指主機名、IP、端口號、狀態頁和健康檢查等信息;標準元數據會被髮布到服務註冊表中,用於服務調用。

  2. 自定義元數據:自定義元數據可以使用eureka.instance.metadata-map配置,這些元數據可以在遠程客戶端中訪問,一般不會改變客戶端的行爲。

5、Eureka Client 源碼分析

在1.c 中介紹了開啓消費者的註解,從此註解入手進行源碼分析:

  1. 梳理幾個關鍵類的關係;
    EurekaDiscoveryClient implements DiscoveryClient implements EurekaClient extends LookupService

  2. 加載信息:Region, Zone;
    通過追蹤源碼發現,在服務註冊時,會依次加載Region和Zone, 一個服務只能有一個Region,但是可以有多個Zone(使用逗號進行分隔);通過調用getAvaliabilityZones()方法獲取 Zone,默認爲 defaultZone。
    在獲取了 Region 和 Zone 的信息之後, 纔開始真正加載 Eureka Server 的具體地址。 它根據傳入的參數按 一 定算法確定加載位於哪 一 個 Zone 配置的 serviceUris 。

小記:

當eureka 與 ribbon 集成時,原本由 ribbon 的 RibbonServerLsit 維護的服務清單將由DiscoveryEnabledNIWSServerList 重寫,使其從 eureka 服務列表中獲取服務信息。同時也會用NIWSDiscoveryPing 替換調 IPing

二、Ribbon

ribbon 通過使用了一 個非常有用的對象RestTemplate 。 該對象會使用 Ribbon 的自動化配置, 同時通過配置 @LoadBalanced 還能夠開啓客戶端負載均衡。

1. RestTemplate

restTemplate 的 GET 調用:兩種方式,getForEntity()、getForObject();

1. getForEntity() 函數:

該方法返回的是 ResponseEntity, 該對象是 Spring對 HTTP 請求響應的封裝。

  • getForEntity(String url, Class responseType, Map urlVariables),使用該方法進行參數綁定時需要在佔位符中指定 Map 中參數的 key 值。使用示例:
Map<String, Object> param = new HashMap<>();
param.put("name", "admin");
restTemplate.getForEntity("http://user-service/user/one?name={name}",String.class,param);

此方法調用後,"admin"會被替換爲佔位符{1}。

  • getForEntity(String url, Class responseType, Object … urlVariables)
    使用示例:
restTemplate.getForEntity("http://user-service/user/one?name={1}",String.class,"admin");

此方法調用後,"admin"會被替換爲佔位符{1}。

  • getForEntity(Uri url, Class responseType)
    使用示例:
Uri uri = UriComponentBuilder.fromUriString("http://user-service/user/one?name={1}").build.expand("admin").encode().toUri();
restTemplate.getForEntity(uri,String.class).getBody();
2. getForObject() 函數:

該方法可以理解爲對 getForEntity 的進一步封裝,它通過 HttpMessageConverterExtractor 對 HTTP 的請求響應體 body 內容進行對象轉換, 實現請求直接返回包裝好的對象內容。也是同樣重載了三個方法,與getForEntity()不同的時,在getForObject(Uri url, Class responseType)方法,不需要再調用getBody()方法。

restTemplate 的 POST 調用:兩種方式,postForEntity()、postForObject()、postForLocation()

1. postForEntity() 函數和 postForObject()函數:

同GET方式類似,都是三種類型的方法重載,不同的是多了一個參數Object request:

postForEntity(String url, Object request, Class responseType, Object... uriVariables)
postForEntity(String url, Object request, Class responseType, Map uriVariables)
postForEntity(URI url, Object request, Class responseType)

注:postForObject()函數類似,不再贅述。需要注意的是新增加的 request參數, 該參數可以是一個普通對象, 也可以是一個HttpEntity對象。 如果是一個普通對象, 而非HttpEntity對象的時候, RestTemplate會將請求對象轉換爲一個HttpEntity對象來處理, 其中Object就是 request的類型, request內容會被視作完整的body來處理;而如果 request是一個HttpEntity對象, 那麼就會被當作一個完成的HTTP請求對象來處理, 這個 request中不僅包含了body的內容, 也包含了 header的內容。使用示例:

ResponseEntity<String> response = restTemplate.postForEntity("http://user-service/user", user, String.class);
String body = response.getBody();
2. postForLocation()函數

該方法實現了以POST請求提交資源, 並返回新 資源的URI,另外相比較postForEntity()和postForObject(),少了一個參數Class responseType:

postForLocation(Stringurl, Object request, Object...urlVariables)
postForLocation(String url, Object request, Map urlVariables)
postForLocation(URI url, Object request)

使用示例;

URI uri = restTemplate.postForLocation("http://user-service/user", user);

restTemplate 的 PUT 調用:put()函數,也是三種方式重載,與GET、POST方式不同的是,PUT沒有返回值,所以沒有Class responseType這個參數:

put(String url, Object request, Object... urlVariables)
put(String url, Object request, Map urlVariables)
put(URI url, Object request)

restTemplate 的 DELETE 調用:delete()函數,通常都將DELETE請求的唯一標識拼接在url中, 所 以DELETE請求也不需要request的body信息,DELETE請求方式和GET非常類似,唯一區別是沒有返回值:

delete(String url, Object ... urlVariables)
delete(String url, Map urlVariables)
delete(URI url)

2、源碼分析

ribbon 是帶有負載均衡功能的服務調用客戶端。使用@LoadBalance註解的RestTemplate,則可以開啓負載均衡配置;

1. 首先查看RibbonAoutConfiguration:

@AutoConfigureAfter(name = "org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration")
@AutoConfigureBefore({LoadBalancerAutoConfiguration.class, AsyncLoadBalancerAutoConfiguration.class})
@EnableConfigurationProperties({RibbonEagerLoadProperties.class, ServerIntrospectorProperties.class})(注:在1.x版本中,是沒有這個配置的)

在類上面有這三個註解,分別設置RibbonAoutConfiguration配置加載之前,之後以及其他的配置。可以看到,在該配置自動加載之前,會加載LoadBalanceAutoCofiguration和AsyncLoadBalanceAutoConfiguration兩個配置類。在這兩個配置類中,都依賴LoadBalancerClient這個接口,它有個唯一實現,就是RibbonLoadBalanceClient。

LoadBalancerAutoConfiguration中根據是否存在“org.springframework.retry.support.RetryTemplate”的信息,如果沒有就LoadBalanceClient來創建LoadBalanceReuqestFactory(向攔截器發出負載請求,並且重試攔截器),然後通過工廠和client創建LoadBalancerInterceptor,如果有,則會直接構建一個LoadBalanceRetryFactory(用於自定義的重試方法)。

在LoadBalancerInterceptor中獲取具體服務實例的時候並沒有使用 LoadBalancerClient 接口中的 choose 函數,而是使用了 Netflix Ribbon 自身的 ILoadBalancer 接口中定義的 chooseServer 函數。

ribbon 默認的使用ILoadBalancer的一個子類的實現類ZoneAwareLoadBalancer

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