在consumer中调用provider服务
生活随笔
收集整理的這篇文章主要介紹了
在consumer中调用provider服务
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
我們已經(jīng)把Consumer的環(huán)境搭建好了,我們也把UserService寫(xiě)好了,我們?cè)賮?lái)看一下,如何在Consumer的UserService當(dāng)中,去調(diào)用Provider當(dāng)中的接口,那么我們要調(diào)服務(wù)的接口,肯定得知道服務(wù)的信息,那么我們?cè)赟pringCloud的微服務(wù)當(dāng)中,如何知道調(diào)用服務(wù)的基本信息呢,比如服務(wù)的IP地址是多少,服務(wù)的端口是什么,那么在SpringCloud當(dāng)中呢,那給我們提供了一個(gè)對(duì)象,這個(gè)對(duì)象叫什么呢,叫LoadBalancerClient,這個(gè)對(duì)象是什么呢,直接把他定義出來(lái),這個(gè)對(duì)象是SpringCloud提供的一個(gè)復(fù)雜均衡的對(duì)象,Ribbon,在SpringCloud當(dāng)中,是通過(guò)Ribbon來(lái)完成負(fù)載均衡的,那么loadBalancerClient,就是Ribbon技術(shù)下的一個(gè)對(duì)象,那么至于負(fù)載均衡器,所以稱(chēng)之為負(fù)載均衡器private LoadBalancerClient loadBalancerClient;//ribbon負(fù)載均衡器我們?cè)诤罄m(xù)中呢,會(huì)去講解他的,那么我們?yōu)槭裁匆玫絃oadBalancerClient呢,因?yàn)槲覀兺ㄟ^(guò)這個(gè)對(duì)象,可以取到我們要調(diào)用服務(wù)的IP地址和端口,那么他是怎么去找IP地址和端口的呢,就是通過(guò)服務(wù)的名稱(chēng),我們的服務(wù)不都有一個(gè)名稱(chēng)嗎,我們provider的,是不是叫springcloud-eureka-provider那么我們現(xiàn)在Consumer的服務(wù),就不能叫跟他相同的名字了,我們應(yīng)該叫springcloud-eureka-consumer我們改過(guò)來(lái),也就是說(shuō),SpringCloud,在幫我們?nèi)ゲ檎倚畔⒌臅r(shí)候呢,就是通過(guò)我們給服務(wù)起的名稱(chēng),然后他會(huì)去注冊(cè)中心里,根據(jù)名稱(chēng)找到這個(gè)服務(wù),并且把服務(wù)的基本信息,封裝到LoadBalancerClient對(duì)象當(dāng)中,然后我們通過(guò)這個(gè)對(duì)象去獲取服務(wù)的基本信息,我們就可以拿到服務(wù)的IP和端口了,那么在這里我們?nèi)绾问褂胠oadBalancerClient去獲取服務(wù)的信息呢,這里我們需要用到一個(gè)對(duì)象,這個(gè)對(duì)象是誰(shuí)呢,這個(gè)對(duì)象叫ServiceInstance,然后咱們叫si,然后this.loadBalancerClient,這是咱們上面定義的對(duì)象,通過(guò)這個(gè)對(duì)象,他下面有choose方法,這個(gè)choose的方法呢,就是通過(guò)我們要查找的接口的名稱(chēng)去做接口的查找,并且返回一個(gè)接口的封裝對(duì)象,ServiceInstance,那么我們要查找的接口的名稱(chēng),是不是Provider里面的springcloud-eureka-provider所以我們現(xiàn)在給服務(wù)其名稱(chēng)的時(shí)候不能隨便亂起ServiceInstance si = this.loadBalancerClient.choose("springcloud-eureka-provider");然后拿到接口的實(shí)例,ServiceInstance以后,我們?cè)撟鍪裁词履?其實(shí)在這個(gè)對(duì)象當(dāng)中,封裝了服務(wù)的基本信息,如IP,端口,那么也就意味著我們通過(guò)這個(gè)對(duì)象,可以取到我們服務(wù)的IP和端口了,然后大家注意,在SpringCloud當(dāng)中呢,他對(duì)于服務(wù)與服務(wù)之間的通信,采用的是URL的形式,所以說(shuō)我們?cè)谶@兒,還得拿著服務(wù)返回回來(lái)的實(shí)例,這個(gè)對(duì)象,去獲取我們的服務(wù)的IP和端口,拼成一個(gè)URL,所以這里我們還得URL的拼接,拼接訪問(wèn)服務(wù)的URLsb.append("http://").append(si.getHost()).append(":").append(si.getPort()).append("/user");其實(shí)我們說(shuō)個(gè)題外話,我感覺(jué)SpringCloud對(duì)于服務(wù)的調(diào)用這一塊,相比我們的Dubbo來(lái)講,要復(fù)雜一些,因?yàn)槲覀兊腄ubbo把對(duì)象直接注入進(jìn)來(lái),@Reference就可以,但是在SpringCloud當(dāng)中呢,他都是通過(guò)URL的方式來(lái)訪問(wèn)接口,有點(diǎn)像什么呢,他的這種形式有點(diǎn)像之前,用過(guò)一個(gè)Apache的工具,叫HttpClient,跟他有點(diǎn)相似,然后通過(guò)StringBuffer去拼接我們的URL,我肯定要拼接一個(gè)HTTP,要通過(guò)http協(xié)議,sb.append("http://").append(si.getHost()).append(":").append(si.getPort()).append("/user");然后接著往后追加,追加什么呢,我們拼的URL是不是應(yīng)該這樣的http://localhost:9090/user我們?cè)赑rovider當(dāng)中,我們的Provider應(yīng)該是啟動(dòng)的,我們的啟動(dòng)器改一下,最好叫ConsumerApplication,然后我們來(lái)運(yùn)行這個(gè)Consumer的實(shí)例,然后我們刷新,然后注意看Provider9090,這個(gè)是不是我們要訪問(wèn)的服務(wù),然后我們看一下里面的Controller,原來(lái)我們通過(guò)瀏覽器地址欄訪問(wèn),是不是這么訪問(wèn)的,是不是一個(gè)叫user的URI10.40.8.152:9090/user是不是拿到這個(gè)信息了,那么我們現(xiàn)在拼接的URL,應(yīng)該是這樣的,在我們的Consumer當(dāng)中,要去訪問(wèn)Provider的地址,最后調(diào)用接口的地址是不是應(yīng)該是這樣的,我們是不是要根據(jù)這個(gè)地址去拼接出來(lái),所以第一個(gè)http,第二個(gè)我們就不能localhost,因?yàn)槟氵@個(gè)服務(wù)的IP,它是不確定的,比如我們使用動(dòng)態(tài)IP,我們服務(wù)多了,我們總不能一個(gè)一個(gè)去記IP地址是多少,每一個(gè)服務(wù)的IP是什么,端口是什么,所以這塊也不用去記住,怎么辦呢,我們通過(guò)loadBalancerClient返回的ServiceInstance對(duì)象里,其實(shí)就包含了我們要調(diào)用服務(wù)的IP和端口,所以我們之前也說(shuō)過(guò),我們做微服務(wù)開(kāi)發(fā)的時(shí)候,不需要你去記住服務(wù)的IP和端口的,因?yàn)榈谝粋€(gè)我們服務(wù)太多了,我們也記不住,第二個(gè)我們有現(xiàn)成的對(duì)象,通過(guò)LoadBalancerClient,返回的ServiceInstance,我們就可以去獲取服務(wù)的基本信息,關(guān)鍵我們要知道你調(diào)用的服務(wù)名稱(chēng)是什么,那么這塊怎么辦呢,正常來(lái)講要拼IP了,我們可以通過(guò)si.getHost(),這個(gè)Host方法呢,返回的就是要調(diào)用的接口來(lái)定義,然后我們還要拼什么,是不是還得拼一個(gè)冒號(hào),然后后面是不是還得拼端口,端口si.getPort(),然后端口拼完了以后,我們的URL就拼完了嗎,很顯然不是的,后面是不是還有這個(gè)信息,這樣我們一個(gè)訪問(wèn)服務(wù)的URL就拼接完畢了,第一步就已經(jīng)搞定了,再來(lái)看,我們拼完URL以后,是不是要像URL發(fā)請(qǐng)求,然后需要一些數(shù)據(jù),那么怎么向URL發(fā)請(qǐng)求呢,我們會(huì)使用SpringMVC提供的一個(gè)對(duì)象,RestTemplate,這個(gè)大家應(yīng)該有用過(guò),應(yīng)該并不陌生,只是封裝了一個(gè)基于Rest模式的一個(gè)對(duì)象,SpringMVC下,那么我們首先要去創(chuàng)建RestTemplate對(duì)象RestTemplate rt = new RestTemplate();然后你去用它發(fā)送請(qǐng)求的時(shí)候,是不是要調(diào)用Provider的這個(gè)Controller,也是會(huì)返回一個(gè)List,也就是我們現(xiàn)在調(diào)用的接口,是有返回值的,那么我們?cè)趺磥?lái)處理這個(gè)返回值呢,我們來(lái)看一下這個(gè)代碼怎么來(lái)編寫(xiě),首先這里我們要定義一個(gè)返回值,有一個(gè)叫ParameterizedTypeReference,我們返回的是什么呢,是一個(gè)List,List里面放的是什么,是User,然后這個(gè)對(duì)象要定義一個(gè)名稱(chēng),比如叫type,我們這里要去new這個(gè)對(duì)象,這塊我們要注意,這個(gè)對(duì)象它是一個(gè)抽象類(lèi),可以看看這個(gè)源碼public abstract class ParameterizedTypeReference<T> {看到了嗎,它是一個(gè)抽象類(lèi),那么抽象類(lèi)能new嗎,跟接口是一樣的,你看后面會(huì)自動(dòng)添加一個(gè)匿名內(nèi)部類(lèi),作為這個(gè)抽象類(lèi)的一個(gè)子類(lèi),那我們把它加上,我們這里也不用加什么方法了,用他里面自帶的方法也夠用了,然后接下來(lái)我們?cè)偃ザx一個(gè)對(duì)象,這個(gè)對(duì)象叫什么呢,叫ResponseEntity,就是他,這個(gè)對(duì)象的作用是什么呢,這個(gè)對(duì)象封裝的就是一個(gè)返回值的二次封裝,這個(gè)對(duì)象當(dāng)中,封裝了返回值信息,然后我們返回的是不是一個(gè)List,然后這塊我們給User,如果用過(guò)RestTemplate的同學(xué),應(yīng)該很熟,這塊我們就不細(xì)說(shuō)了,然后呢response,等于new誰(shuí)呢,用我們的restTemplate,因?yàn)樗前l(fā)送URL請(qǐng)求的模板對(duì)象,有一個(gè)exchange方法ResponseEntity<List<User>> response = rt.exchange(sb.toString(),HttpMethod.GET, null, type);然后你看exchange方法有這么多,我們隨便寫(xiě)一個(gè),這里我們用的是四個(gè)參數(shù)的,我們來(lái)看一下,第一個(gè)參數(shù)是什么呢,就是你要調(diào)用服務(wù)的URL,這個(gè)URL我們是不是已經(jīng)拼接到buffer里面了,所以我們直接sb.toString()就可以了,他要的是一個(gè)字符串,第二個(gè)是一個(gè)method,method表示什么含義呢,你現(xiàn)在要用什么請(qǐng)求方式去請(qǐng)求他,用get還是post,那我們可以用GET,GET怎么寫(xiě)呢,有一個(gè)常量類(lèi),是一個(gè)枚舉,叫HttpMethod,在這個(gè)枚舉下呢,有很多在HTTP協(xié)議下發(fā)送的很多類(lèi)型,那我們?cè)谶@里選擇GET,第三個(gè)參數(shù),你請(qǐng)求有沒(méi)有參數(shù)傳遞,那我們現(xiàn)在是沒(méi)有任何參數(shù)的,所以我們這塊為空,第三個(gè)參數(shù)表示請(qǐng)求參數(shù)的,然后第四個(gè),responseType,這個(gè) 表示什么意思呢,你返回值的這個(gè)對(duì)象,用什么類(lèi)型來(lái)包裝,在這里我們專(zhuān)門(mén)定義了一個(gè)返回值類(lèi)型的對(duì)象,ParameterizedTypeReference,這個(gè)時(shí)候我們就把這個(gè)對(duì)象放到里面,然后這個(gè)對(duì)象,他返回的response,就是封裝了我們調(diào)用接口后,返回的一個(gè)返回值的二次封裝的對(duì)象,那我們這里怎么去取呢,很簡(jiǎn)單,我們現(xiàn)在,我們看一下,我們調(diào)用Provider的UserController,是不是返回一個(gè)List,那么這樣的話,在我的Consumer當(dāng)中,他返回的也得是一個(gè)List,我這里泛型定義的時(shí)候是List,那我們就可以這么寫(xiě)List<User> list =response.getBody();然后在這里把list返回,這樣我們通過(guò)Consumer中的Service去調(diào)用Provider服務(wù)的一個(gè)代碼,就寫(xiě)完了,所以相比之下這個(gè)代碼呢,這個(gè)代碼片段還是比較多的,當(dāng)然你也可以自己封裝,比如你可以把這些代碼做一個(gè)封裝,然后只要根據(jù)給定的參數(shù),直接在你封裝的工具類(lèi)里直接做拼接了,或者做一些發(fā)送就可以了,你自己回球定義一個(gè)工具類(lèi),進(jìn)行封裝就可以了,我們現(xiàn)在把Consumer的Service代碼copy過(guò)來(lái),先粘到筆記當(dāng)中,這一塊大家要認(rèn)真的看一看,因?yàn)槲覀兎?wù)與服務(wù)之間的通信,可以說(shuō)在微服務(wù)開(kāi)發(fā)當(dāng)中,是非常重要的,因?yàn)槲覀兎?wù)和服務(wù)之間肯定是要做調(diào)用的,然后我們?cè)賮?lái)看,這一部分改完了,但是Consumer的Controller還沒(méi)有改完我們直接寫(xiě)個(gè)consumer,我們是不是先得把業(yè)務(wù)層注入進(jìn)來(lái)@Autowired
private UserService userService;然后我們這里要做的就是調(diào)用userService下的getUsers方法,這個(gè)是他的Controller,那么我們的Consumer和Provider寫(xiě)完以后呢,就可以進(jìn)行測(cè)試了,現(xiàn)在沒(méi)有任何服務(wù),我們先把Provider啟動(dòng),觀察控制臺(tái),然后我們?cè)偃?dòng)Consumer,那么Consumer也啟動(dòng)好了,接下來(lái)我們是不是就可以訪問(wèn)Consumer的Controller了,他的端口是多少,他的端口是9091,這個(gè)是9091下面的一個(gè)consumerlocalhost:9091/consumer這里出了一個(gè)異常,我們來(lái)看一下是不是拿到了,剛才應(yīng)該是我們的服務(wù)還沒(méi)有啟動(dòng)完畢,那么我們看,現(xiàn)在我們看到的數(shù)據(jù)就是從Consumer當(dāng)中拿到的,那么Consumer又是從哪里拿到的呢,在他的Service當(dāng)中,去調(diào)用我們Provider服務(wù)當(dāng)中的接口,在這個(gè)接口當(dāng)中,做了一個(gè)數(shù)據(jù)的定義,然后通過(guò)Provider將數(shù)據(jù)返回給我們的Consumer,所以我們看到的數(shù)據(jù)就是Provider返回回來(lái)的,那么在服務(wù)與服務(wù)之間調(diào)用的當(dāng)中呢,大家需要重點(diǎn)了解的,重點(diǎn)注意的就是,LoadBalancerClient這個(gè)對(duì)象,我們通過(guò)這個(gè)對(duì)象,根據(jù)服務(wù)的名稱(chēng)返回一個(gè)實(shí)例,我們通過(guò)這個(gè)實(shí)例,是可以拿到服務(wù)的IP和端口,然后我們對(duì)服務(wù)的IP和端口進(jìn)行一個(gè)拼接,變成一個(gè)完整的訪問(wèn)服務(wù)的URL,然后我們?cè)偻ㄟ^(guò)SpringMVC提供的RestTemplate,就可以去請(qǐng)求我們的服務(wù)了,Consumer去請(qǐng)求Provider的案例的一個(gè)講解
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.learn.cloud</groupId><artifactId>springcloud-eureka-consumer</artifactId><version>0.0.1-SNAPSHOT</version><packaging>jar</packaging><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.12.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version></properties> <dependencyManagement><dependencies><dependency> <groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>Dalston.SR1</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-eureka</artifactId></dependency></dependencies><!-- 這個(gè)插件,可以將應(yīng)用打包成一個(gè)可執(zhí)行的jar包 --><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
server.port=9091
eureka.client.serviceUrl.defaultZone=http://10.40.8.152:8761/eureka
spring.application.name=springcloud-eureka-consumer
eureka.instance.prefer-ip-address=true
eureka.instance.instance-id=${spring.application.name}:${spring.cloud.client.ipAddress}:${spring.application.instance_id:${server.port}}
package com.learn.pojo;public class User {private int userid;private String username;private int userage;public int getUserid() {return userid;}public void setUserid(int userid) {this.userid = userid;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public int getUserage() {return userage;}public void setUserage(int userage) {this.userage = userage;}public User(int userid, String username, int userage) {super();this.userid = userid;this.username = username;this.userage = userage;}public User() {super();// TODO Auto-generated constructor stub}}
package com.learn.service;import java.util.List;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;import com.learn.pojo.User;@Service
public class UserService {@Autowiredprivate LoadBalancerClient loadBalancerClient;//ribbon負(fù)載均衡器public List<User> getUsers(){//選擇調(diào)用的服務(wù)的名稱(chēng)//ServiceInstance 封裝了服務(wù)的基本信息,如 IP,端口ServiceInstance si = this.loadBalancerClient.choose("springcloud-eureka-provider");//拼接訪問(wèn)服務(wù)的URLStringBuffer sb = new StringBuffer();//http://localhost:9090/usersb.append("http://").append(si.getHost()).append(":").append(si.getPort()).append("/user");//springMVC RestTemplateRestTemplate rt = new RestTemplate();ParameterizedTypeReference<List<User>> type = new ParameterizedTypeReference<List<User>>() {};//ResponseEntity:封裝了返回值信息ResponseEntity<List<User>> response = rt.exchange(sb.toString(),HttpMethod.GET, null, type);List<User> list =response.getBody();return list;}
}
package com.learn.controller;import java.util.List;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import com.learn.pojo.User;
import com.learn.service.UserService;@RestController
public class UserController {@Autowiredprivate UserService userService;@RequestMapping("/consumer")public List<User> getUsers(){return this.userService.getUsers();}
}
package com.learn;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;@EnableEurekaClient
@SpringBootApplication
public class ConsumerApplication {public static void main(String[] args) {SpringApplication.run(ConsumerApplication.class, args);}
}
?
總結(jié)
以上是生活随笔為你收集整理的在consumer中调用provider服务的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 创建consumer服务
- 下一篇: eureka架构图原理