javascript
怎么看调用的接口_SpringCloud服务间调用
本篇簡介
在上一篇我們介紹了SpringCloud中的注冊中心組件Eureka。Eureka的作用是做服務注冊與發現的,目的是讓不同的服務與服務之間都可以通過注冊中心進行間接關聯,并且可以通過注冊中心有效的管理不同服務與服務的運行狀態。但在微服務的架構中,服務與服務只知道對方的服務地址是沒有用的,它們的本質還是需要彼此進行通信的,這也是微服務最核心的功能之一。
既然提到了服務與服務之間的通信,那我們自然而然會想到大名鼎鼎的HttpClient。因為在其它的項目架構中我們基本都可以通過它來進行不同服務與服務之間的調用。在SpringCloud中我們依然可以使用HttpClient進行服務與服務調用,只不過如果采用HttpClient調用的話,會有一些弊端。例如: 如果同一個服務有多個負載的話,采用HttpClient調用時,沒有辦法處理負載均衡的問題。還有另一個問題就是HttpClient只是提供了核心調用的方法并沒有對調用進行封裝,所以在使用上不太方便,需要自己對HttpClient進行簡單的封裝。
調用方式
在SpringCloud中為了解決服務與服務調用的問題,于是提供了兩種方式來進行調用。也就是RestTemplate和Feign。雖然從名字上看這兩種調用的方式不同,但在底層還是和HttpClient一樣,采用http的方式進行調用的。只不過是對HttpClient進行的封裝。下面我們來詳細的介紹一下這兩種方式的區別,我們首先看一下RestTemplate的方式。
RestTemplate方式調用
RestTemplate
為了方便掩飾我們服務間的調用,所以我們需要創建三個項目。它們分別為eureka(注冊中心)、server(服務提供方)、client(服務調用方)。因為上一篇中我們已經介紹了eureka的相關內容。所以在這一篇中我們將不在做過多的介紹了。下面我們看一下server端的配置。因為實際上Server端和Client端是相互的。不一定client端一定要調用server端。server端一樣可以調用client端。但對于eureka來說,它們都是client端。因為上一篇中我們已經介紹了eureka是分為server端和client端的,并且已經介紹client端相關內容。所以我們下面我們直接看一下server端的配置內容:
eureka:client:
service-url:
defaultZone: http://127.0.0.1:8761/eureka/
spring:
application:
name: jilinwula-springcloud-feign-server
server:
port: 8082
為了掩飾我們服務間的調用,所以我們需要創建一個Controller,并編寫一個簡單的接口來供client調用。下面為server的源碼。
package com.jilinwula.feign.controller;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/server")
public class Controller {
@GetMapping("/get")
public Object get() {
Map<String, String> map = new HashMap<String, String>();
map.put("code", "0");
map.put("msg", "success");
map.put("data", "吉林烏拉");
return map;
}
}
下面我們訪問一下這個接口看看,是否能正確返回數據。(備注:注意別忘記了在啟動類上添加@EnableEurekaClient注解。)下面我們還是使用.http文件的方式發起接口請求。
GET?http://127.0.0.1:8082/server/get返回結果:
GET http://127.0.0.1:8082/server/getHTTP/1.1 200
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Fri, 15 Mar 2019 08:20:33 GMT
{
"msg": "success",
"code": "0",
"data": "吉林烏拉"
}
Response code: 200; Time: 65ms; Content length: 42 bytes
我們看已經成功的返回了接口的數據了。下面我們看一下eureka。看看是否成功的檢測到了server端的服務。下面為eureka管理界面地址:
http://127.0.0.1:8761
我們看eureka已經成功的檢測到了server端注冊成功了。下面我們看一下client端的代碼,我們還是向server端一樣,創建一個Controller,并編寫一個接口。下面為具體配置及代碼。
application.yml:
eureka:client:
service-url:
defaultZone: http://127.0.0.1:8761/eureka/
spring:
application:
name: jilinwula-springcloud-feign-client
server:
port: 8081
Controller:
package com.jilinwula.feign.controller;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/client")
public class Controller {
@GetMapping("/get")
public Object get() {
Map<String, String> map = new HashMap<String, String>();
map.put("code", "0");
map.put("msg", "success");
map.put("data", "吉林烏拉");
return map;
}
}
下面為訪問的接口地址:
GET?http://127.0.0.1:8081/client/get返回結果:
GET http://127.0.0.1:8081/client/getHTTP/1.1 200
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Fri, 15 Mar 2019 08:56:42 GMT
{
"msg": "success",
"code": "0",
"data": "吉林烏拉"
}
Response code: 200; Time: 273ms; Content length: 42 bytes
現在我們在訪問一下Eureka地址看一下Client服務注冊的是否成功。
http://127.0.0.1:8761
RestTemplate實例化
我們發現server和client端都已經成功的在注冊中心注冊成功了。這也就是我們接下來要介紹的服務間調用的前提條件。在開發Spring項目時我們知道如果我們想要使有哪個類或者哪個對象,那就需要在xml中或者用注解的方式實例化對象。所以既然我們打算使用RestTemplate類進行調用,那我們必須要先實例化RestTemplate類。下面我們就看一下怎么在實例化RestTemplate類。因為不論采用的是RestTemplate方式調用還是采用Feign方式,均是在服務的client端進行開發的,在服務的server是無需做任何更改的。所以下面我們看一下client端的改動。下面為項目源碼:
package com.jilinwula.feign;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableEurekaClient
public class JilinwulaSpringcloudFeignClientApplication {
public static void main(String[] args) {
SpringApplication.run(JilinwulaSpringcloudFeignClientApplication.class, args);
}
@Bean
public RestTemplate initRestTemplate() {
return new RestTemplate();
}
}
RestTemplate調用方式一
為了掩飾方便我們直接在啟動類上添加了一個@Bean注解。然后手動實例化了一個對象,并且要特別注意,在使用RestTemplate時,必須要先實例化,否則會拋出空指針異常。下面我們演示一下怎么使用RestTemplate來調用server端的接口。下面為Controller中的代碼的改動。
package com.jilinwula.feign.controller;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@RequestMapping("/client")
public class Controller {
@Autowired
private RestTemplate template;
@GetMapping("/get")
public Object get() {
String result = template.getForObject("http://127.0.0.1:8082/server/get", String.class);
return result;
}
}
上面的代碼比較簡單,我們就不詳細的介紹了,主要是RestTemplate中提供了getForObject方法(實際上RestTemplate提供了很多種調用的方法,主要分為Get或者Post),可以指定要調用接口的地址,指定返回的值的類型。然后就會直接返回要調用接口的結果。下面我們測試一下,還是調用client接口,看看能否正確的返回server端的數據。
http://127.0.0.1:8081/client/get返回結果:
GET http://127.0.0.1:8081/client/getHTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
Content-Length: 50
Date: Fri, 15 Mar 2019 09:42:02 GMT
{"msg":"success","code":"0","data":"吉林烏拉"}
Response code: 200; Time: 362ms; Content length: 42 bytes
RestTemplate調用方式二
我們看結果,已經成功的返回的server端的數據了,雖然返回的數據沒有格式化,但返回的結果數據確實是server端的數據。這也就是RestTemplate的簡單使用。但上述的代碼是有弊端的,因為我們直接將調用的server端的接口地址直接寫死了,這樣當服務接口變更時,是需要更改客戶端代碼的,這顯示是不合理的。那怎么辦呢?這時就知道注冊中心的好處了。因為注冊中心知道所有服務的地址,這樣我們通過注冊中心就可以知道server端的接口地址,這樣就避免了server端服務更改時,要同步更改client代碼了。下面我們在優化一下代碼,看看怎么通過注冊中心來獲取server端的地址。
package com.jilinwula.feign.controller;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@RequestMapping("/client")
public class Controller {
@Autowired
private RestTemplate template;
@Autowired
private LoadBalancerClient loadBalancerClient;
@GetMapping("/get")
public Object get() {
ServiceInstance serviceInstance = loadBalancerClient.choose("jilinwula-springcloud-feign-server");
String url = String.format("http://%s:%s/server/get", serviceInstance.getHost(), serviceInstance.getPort());
String result = template.getForObject(url, String.class);
return result;
}
}
在SpringClourd中提供了LoadBalancerClient接口。通過這個接口我們可以通過用戶中心的Application的名字來獲取該服務的地址和端口。也就是下圖中紅色標紅的名字(注意名字大小寫)。
通過這些我們就可以獲取到完整的服務接口地址了,這樣就可以直接通過RestTemplate進行接口調用了。下面我們在看一下調用的結果。接口地址:
GET?http://127.0.0.1:8081/client/get返回結果:
GET http://127.0.0.1:8081/client/getHTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
Content-Length: 50
Date: Sat, 16 Mar 2019 09:08:32 GMT
{"msg":"success","code":"0","data":"吉林烏拉"}
Response code: 200; Time: 53ms; Content length: 42 bytes
RestTemplate調用方式三
這樣我們就解決了第一次服務接口地址寫死的問題了。但上述的接口還有一個弊端就是我們每次調用服務時都要先通過Application的名字來獲取ServiceInstance對象,然后才可以發起接口調用。實際上在SpringCloud中為我們提供了@LoadBalanced注解,只要將該注解添加到RestTemplate中的獲取的地方就可以了。下面為具體修改:
啟動類:
package com.jilinwula.feign;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableEurekaClient
public class JilinwulaSpringcloudFeignClientApplication {
public static void main(String[] args) {
SpringApplication.run(JilinwulaSpringcloudFeignClientApplication.class, args);
}
@Bean
@LoadBalanced
public RestTemplate initRestTemplate() {
return new RestTemplate();
}
}
我們在RestTemplate實例化的地方添加了@LoadBalanced注解,這樣在我們使用RestTemplate時就該注解就會自動將調用接口的地址替換成真正的服務地址。下面我們看一下Controller中的改動:
package com.jilinwula.feign.controller;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@RequestMapping("/client")
public class Controller {
@Autowired
private RestTemplate template;
@GetMapping("/get")
public Object get() {
String url = String.format("http://%s/server/get", "jilinwula-springcloud-feign-server");
String result = template.getForObject(url, String.class);
return result;
}
}
代碼和第一次的代碼基本一樣,唯一的區別就是獲取服務地址和端口的地方替換成了注冊中心中的Application的名字,并且我們的RestTemplate在使用上和第一次沒有任何區別,只是在url中不同。下面我們看一下返回的結果。
GET http://127.0.0.1:8081/client/getHTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
Content-Length: 50
Date: Sat, 16 Mar 2019 09:55:46 GMT
{"msg":"success","code":"0","data":"吉林烏拉"}
Response code: 200; Time: 635ms; Content length: 42 bytes
默認負載均衡策略
上述內容就是使用RestTemplate來進行服務間調用的方式。并且采用這樣的方式可以很方便的解決負載均衡的問題。因為@LoadBalanced注解會自動采用默信的負載策略。下面我們看驗證一下SpringCloud默認的負載策略是什么。為了掩飾負載策略,所以我們在新增一個server服務,并且為了掩飾這兩個server返回結果的不同,我們故意讓接口返回的數據不一致,來方便我們測試。下面為新增的server服務端的配置信息及controller源碼。
application.yml:
eureka:client:
service-url:
defaultZone: http://127.0.0.1:8761/eureka/
spring:
application:
name: jilinwula-springcloud-feign-server
server:
port: 8083
Controller:
package com.jilinwula.feign.controller;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/server")
public class Controller {
@GetMapping("/get")
public Object get() {
Map<String, String> map = new HashMap<String, String>();
map.put("code", "0");
map.put("msg", "success");
map.put("data", "jilinwula");
return map;
}
}
調用以下接口:
GET?http://127.0.0.1:8083/server/get返回結果:
GET http://127.0.0.1:8083/server/getHTTP/1.1 200
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sat, 16 Mar 2019 10:49:07 GMT
{
"msg": "success",
"code": "0",
"data": "jilinwula"
}
Response code: 200; Time: 100ms; Content length: 47 bytes
現在我們訪問一下注冊中心看一下現在注冊中心的變化。注冊中心地址:
http://127.0.0.1:8761
我們看上圖注冊中心已經顯示Application名字為JILINWULA-SPRINGCLOUD-FEIGN-SERVER的有兩個服務已經注冊成功了。下面我們直接調用client中的接口,看一下client默認會返回哪個server端的信息。client接口地址:
GET?http://127.0.0.1:8081/client/get返回結果:
GET http://127.0.0.1:8081/client/getHTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
Content-Length: 47
Date: Sat, 16 Mar 2019 10:58:39 GMT
{"msg":"success","code":"0","data":"jilinwula"}
Response code: 200; Time: 24ms; Content length: 47 bytes
看上面返回的結果是server2的接口數據。我們在請求一下接口在看一下返回的結果:
GET http://127.0.0.1:8081/client/getHTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
Content-Length: 50
Date: Sat, 16 Mar 2019 11:01:01 GMT
{"msg":"success","code":"0","data":"吉林烏拉"}
Response code: 200; Time: 15ms; Content length: 42 bytes
更改默認負載均衡策略一
我們看這回返回的接口數據就是第一個server端的信息了。并且我們可以頻繁的調用client中的接口,并觀察發現它們會交替返回的。所以我們基本可以確定SpringCloud默認的負載策略為輪詢方式。也就是會依次調用。在SpringCloud中提供了很多種負載策略。比較常見的為:隨機、輪詢、哈希、權重等。下面我們介紹一下怎么修改默認的負載策略。SpringCloud底層采用的是Ribbon來實現的負載均衡。Ribbon是一個負載均衡器,Ribbon的核心組件為IRule,它也就是所有負載策略的父類。下面為IRule接口的源碼:
package com.netflix.loadbalancer;public interface IRule {
Server choose(Object var1);
void setLoadBalancer(ILoadBalancer var1);
ILoadBalancer getLoadBalancer();
}
該類只提供了3個方法,它們的作用分別是選擇一個服務名字、設置ILoadBalancer和返回ILoadBalancer。下面我們看一下IRule接口的常見策略子類。常見的有RandomRule、RoundRobinRule、WeightedResponseTimeRule等。分別對應著隨機、輪詢、和權重。下面我們看一下怎么更改默認的策略方式。更改默認策略也是在client端中操作的,所以我們看一下client端的代碼更改:
package com.jilinwula.feign;import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableEurekaClient
public class JilinwulaSpringcloudFeignClientApplication {
public static void main(String[] args) {
SpringApplication.run(JilinwulaSpringcloudFeignClientApplication.class, args);
}
@Bean
@LoadBalanced
public RestTemplate initRestTemplate() {
return new RestTemplate();
}
@Bean
public IRule initIRule() {
return new RandomRule();
}
}
我們在啟動類上新實例化了一個IRule對象,并且指定該對象實例化的子類為RandomRule,也就是隨機的方式。所以當我們Client端啟動服務調用服務時,就會采用隨機的方式進行調用,因為我們已經將IRule對象默認的實例化方式更改了。下面我們測試一下,繼續訪問Client端接口:
GET?http://127.0.0.1:8081/client/get返回結果:
GET http://127.0.0.1:8081/client/getHTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
Content-Length: 50
Date: Sat, 16 Mar 2019 11:36:01 GMT
{"msg":"success","code":"0","data":"吉林烏拉"}
Response code: 200; Time: 15ms; Content length: 42 bytes
更改默認負載均衡策略二
在這里我們就不依依演示了,但如果我們多次調用接口就會發現,Client接口返回的結果不在是輪詢的方式了,而是變成了隨機了,這就說明我們已經成功的將SpringCloud默認的負載策略更改了。下面我們換一種方式來更改默認的負載策略。這種方式和上面的有所不同,而是在配置文件中配置的,下面為具體的配置。(備注:為了不影響測試效果,我們需要將剛剛在啟動類中的實例化的IRule注釋掉)
eureka:client:
service-url:
defaultZone: http://127.0.0.1:8761/eureka/
spring:
application:
name: jilinwula-springcloud-feign-client
server:
port: 8081
jilinwula-springcloud-feign-server:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
我們在配置文件中指定了注冊中心中的server端的Application名字,然后指定了默認的負載策略類。下面我們測試一下。訪問以下接口:
GET?http://127.0.0.1:8081/client/get返回結果:
GET http://127.0.0.1:8081/client/getHTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
Content-Length: 50
Date: Sat, 16 Mar 2019 11:54:42 GMT
{"msg":"success","code":"0","data":"吉林烏拉"}
Response code: 200; Time: 13ms; Content length: 42 bytes
Feign方式調用
我們在實際的開發中,可以使用上述兩種方式來更改SpringCloud中默認的負載策略。下面我們看一下SpringCloud中另一種服務間調用方式也就是Feign方式。使用Feign方式和RestTemplate不同,我們需要先添加Feign的依賴,具體依賴如下(備注:該依賴同樣是在client端添加的):
pom.xml:
<dependency><groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
<version>2.1.1.RELEASEversion>
dependency>
其次我們還需要在啟動類中添加@EnableFeignClients注解。具體代碼如下:
package com.jilinwula.feign;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class JilinwulaSpringcloudFeignClientApplication {
public static void main(String[] args) {
SpringApplication.run(JilinwulaSpringcloudFeignClientApplication.class, args);
}
}
接下來我們需要在Client端創建一個新的接口并定義Client端需要調用的服務方法。具體代碼如下:
package com.jilinwula.feign.server;import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
@FeignClient(name = "jilinwula-springcloud-feign-server")
public interface ServerApi {
@GetMapping("/server/get")
String get();
}
上述接口基本上和server端的Controller一致,唯一的不同就是我們指定了@FeignClient注解,該注解的需要指定一個名字,也就是注冊中心中Applicaiton的名字,也就是要調用的服務名字。下面我們看一下Controller中的代碼更改:
package com.jilinwula.feign.controller;import com.jilinwula.feign.server.ServerApi;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/client")
public class Controller {
@Autowired
private ServerApi serverApi;
@GetMapping("/get")
public Object get() {
String result = serverApi.get();
return result;
}
}
我們在Controller中直接使用了我們自定義的接口,并直接調用我們接口中定義的方法,下面我們調用一下Client接口看看這樣的方式是否可以調用成功。接口地址:
GET?http://127.0.0.1:8081/client/get返回結果:
GET http://127.0.0.1:8081/client/getHTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
Content-Length: 50
Date: Sat, 16 Mar 2019 12:54:50 GMT
{"msg":"success","code":"0","data":"吉林烏拉"}
Response code: 200; Time: 14ms; Content length: 42 bytes
我們看這樣的方式也是可以成功的調用server端的接口的,只不過這樣的方式可能會讓覺的不太方便,因為這樣的方式是需要Client端定義和Server端一樣的接口的。
上述內容就是本篇的全部內容,在實際的項目開發中,這兩種方式均可實現服務與服務間的調用,并且這兩種方式都有彼此的弊端,所以并沒有特別推薦的方式。在下一篇中,我們將介紹配置中心相關內容,謝謝。
項目源碼
https://github.com/jilinwula/jilinwula-springcloud-feign
原文鏈接
http://jilinwula.com/article/...
總結
以上是生活随笔為你收集整理的怎么看调用的接口_SpringCloud服务间调用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 华为鸿蒙用着怎么样,首批华为鸿蒙用户体验
- 下一篇: linux上修改html,linux进程