在consumer中调用provider服务
生活随笔
收集整理的這篇文章主要介紹了
在consumer中调用provider服务
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
我們已經(jīng)把Consumer的環(huán)境搭建好了,我們也把UserService寫好了,我們再來看一下,如何在Consumer的UserService當中,去調(diào)用Provider當中的接口,那么我們要調(diào)服務的接口,肯定得知道服務的信息,那么我們在SpringCloud的微服務當中,如何知道調(diào)用服務的基本信息呢,比如服務的IP地址是多少,服務的端口是什么,那么在SpringCloud當中呢,那給我們提供了一個對象,這個對象叫什么呢,叫LoadBalancerClient,這個對象是什么呢,直接把他定義出來,這個對象是SpringCloud提供的一個復雜均衡的對象,Ribbon,在SpringCloud當中,是通過Ribbon來完成負載均衡的,那么loadBalancerClient,就是Ribbon技術下的一個對象,那么至于負載均衡器,所以稱之為負載均衡器private LoadBalancerClient loadBalancerClient;//ribbon負載均衡器我們在后續(xù)中呢,會去講解他的,那么我們?yōu)槭裁匆玫絃oadBalancerClient呢,因為我們通過這個對象,可以取到我們要調(diào)用服務的IP地址和端口,那么他是怎么去找IP地址和端口的呢,就是通過服務的名稱,我們的服務不都有一個名稱嗎,我們provider的,是不是叫springcloud-eureka-provider那么我們現(xiàn)在Consumer的服務,就不能叫跟他相同的名字了,我們應該叫springcloud-eureka-consumer我們改過來,也就是說,SpringCloud,在幫我們?nèi)ゲ檎倚畔⒌臅r候呢,就是通過我們給服務起的名稱,然后他會去注冊中心里,根據(jù)名稱找到這個服務,并且把服務的基本信息,封裝到LoadBalancerClient對象當中,然后我們通過這個對象去獲取服務的基本信息,我們就可以拿到服務的IP和端口了,那么在這里我們?nèi)绾问褂胠oadBalancerClient去獲取服務的信息呢,這里我們需要用到一個對象,這個對象是誰呢,這個對象叫ServiceInstance,然后咱們叫si,然后this.loadBalancerClient,這是咱們上面定義的對象,通過這個對象,他下面有choose方法,這個choose的方法呢,就是通過我們要查找的接口的名稱去做接口的查找,并且返回一個接口的封裝對象,ServiceInstance,那么我們要查找的接口的名稱,是不是Provider里面的springcloud-eureka-provider所以我們現(xiàn)在給服務其名稱的時候不能隨便亂起ServiceInstance si = this.loadBalancerClient.choose("springcloud-eureka-provider");然后拿到接口的實例,ServiceInstance以后,我們該做什么事呢,其實在這個對象當中,封裝了服務的基本信息,如IP,端口,那么也就意味著我們通過這個對象,可以取到我們服務的IP和端口了,然后大家注意,在SpringCloud當中呢,他對于服務與服務之間的通信,采用的是URL的形式,所以說我們在這兒,還得拿著服務返回回來的實例,這個對象,去獲取我們的服務的IP和端口,拼成一個URL,所以這里我們還得URL的拼接,拼接訪問服務的URLsb.append("http://").append(si.getHost()).append(":").append(si.getPort()).append("/user");其實我們說個題外話,我感覺SpringCloud對于服務的調(diào)用這一塊,相比我們的Dubbo來講,要復雜一些,因為我們的Dubbo把對象直接注入進來,@Reference就可以,但是在SpringCloud當中呢,他都是通過URL的方式來訪問接口,有點像什么呢,他的這種形式有點像之前,用過一個Apache的工具,叫HttpClient,跟他有點相似,然后通過StringBuffer去拼接我們的URL,我肯定要拼接一個HTTP,要通過http協(xié)議,sb.append("http://").append(si.getHost()).append(":").append(si.getPort()).append("/user");然后接著往后追加,追加什么呢,我們拼的URL是不是應該這樣的http://localhost:9090/user我們在Provider當中,我們的Provider應該是啟動的,我們的啟動器改一下,最好叫ConsumerApplication,然后我們來運行這個Consumer的實例,然后我們刷新,然后注意看Provider9090,這個是不是我們要訪問的服務,然后我們看一下里面的Controller,原來我們通過瀏覽器地址欄訪問,是不是這么訪問的,是不是一個叫user的URI10.40.8.152:9090/user是不是拿到這個信息了,那么我們現(xiàn)在拼接的URL,應該是這樣的,在我們的Consumer當中,要去訪問Provider的地址,最后調(diào)用接口的地址是不是應該是這樣的,我們是不是要根據(jù)這個地址去拼接出來,所以第一個http,第二個我們就不能localhost,因為你這個服務的IP,它是不確定的,比如我們使用動態(tài)IP,我們服務多了,我們總不能一個一個去記IP地址是多少,每一個服務的IP是什么,端口是什么,所以這塊也不用去記住,怎么辦呢,我們通過loadBalancerClient返回的ServiceInstance對象里,其實就包含了我們要調(diào)用服務的IP和端口,所以我們之前也說過,我們做微服務開發(fā)的時候,不需要你去記住服務的IP和端口的,因為第一個我們服務太多了,我們也記不住,第二個我們有現(xiàn)成的對象,通過LoadBalancerClient,返回的ServiceInstance,我們就可以去獲取服務的基本信息,關鍵我們要知道你調(diào)用的服務名稱是什么,那么這塊怎么辦呢,正常來講要拼IP了,我們可以通過si.getHost(),這個Host方法呢,返回的就是要調(diào)用的接口來定義,然后我們還要拼什么,是不是還得拼一個冒號,然后后面是不是還得拼端口,端口si.getPort(),然后端口拼完了以后,我們的URL就拼完了嗎,很顯然不是的,后面是不是還有這個信息,這樣我們一個訪問服務的URL就拼接完畢了,第一步就已經(jīng)搞定了,再來看,我們拼完URL以后,是不是要像URL發(fā)請求,然后需要一些數(shù)據(jù),那么怎么向URL發(fā)請求呢,我們會使用SpringMVC提供的一個對象,RestTemplate,這個大家應該有用過,應該并不陌生,只是封裝了一個基于Rest模式的一個對象,SpringMVC下,那么我們首先要去創(chuàng)建RestTemplate對象RestTemplate rt = new RestTemplate();然后你去用它發(fā)送請求的時候,是不是要調(diào)用Provider的這個Controller,也是會返回一個List,也就是我們現(xiàn)在調(diào)用的接口,是有返回值的,那么我們怎么來處理這個返回值呢,我們來看一下這個代碼怎么來編寫,首先這里我們要定義一個返回值,有一個叫ParameterizedTypeReference,我們返回的是什么呢,是一個List,List里面放的是什么,是User,然后這個對象要定義一個名稱,比如叫type,我們這里要去new這個對象,這塊我們要注意,這個對象它是一個抽象類,可以看看這個源碼public abstract class ParameterizedTypeReference<T> {看到了嗎,它是一個抽象類,那么抽象類能new嗎,跟接口是一樣的,你看后面會自動添加一個匿名內(nèi)部類,作為這個抽象類的一個子類,那我們把它加上,我們這里也不用加什么方法了,用他里面自帶的方法也夠用了,然后接下來我們再去定義一個對象,這個對象叫什么呢,叫ResponseEntity,就是他,這個對象的作用是什么呢,這個對象封裝的就是一個返回值的二次封裝,這個對象當中,封裝了返回值信息,然后我們返回的是不是一個List,然后這塊我們給User,如果用過RestTemplate的同學,應該很熟,這塊我們就不細說了,然后呢response,等于new誰呢,用我們的restTemplate,因為它是發(fā)送URL請求的模板對象,有一個exchange方法ResponseEntity<List<User>> response = rt.exchange(sb.toString(),HttpMethod.GET, null, type);然后你看exchange方法有這么多,我們隨便寫一個,這里我們用的是四個參數(shù)的,我們來看一下,第一個參數(shù)是什么呢,就是你要調(diào)用服務的URL,這個URL我們是不是已經(jīng)拼接到buffer里面了,所以我們直接sb.toString()就可以了,他要的是一個字符串,第二個是一個method,method表示什么含義呢,你現(xiàn)在要用什么請求方式去請求他,用get還是post,那我們可以用GET,GET怎么寫呢,有一個常量類,是一個枚舉,叫HttpMethod,在這個枚舉下呢,有很多在HTTP協(xié)議下發(fā)送的很多類型,那我們在這里選擇GET,第三個參數(shù),你請求有沒有參數(shù)傳遞,那我們現(xiàn)在是沒有任何參數(shù)的,所以我們這塊為空,第三個參數(shù)表示請求參數(shù)的,然后第四個,responseType,這個 表示什么意思呢,你返回值的這個對象,用什么類型來包裝,在這里我們專門定義了一個返回值類型的對象,ParameterizedTypeReference,這個時候我們就把這個對象放到里面,然后這個對象,他返回的response,就是封裝了我們調(diào)用接口后,返回的一個返回值的二次封裝的對象,那我們這里怎么去取呢,很簡單,我們現(xiàn)在,我們看一下,我們調(diào)用Provider的UserController,是不是返回一個List,那么這樣的話,在我的Consumer當中,他返回的也得是一個List,我這里泛型定義的時候是List,那我們就可以這么寫List<User> list =response.getBody();然后在這里把list返回,這樣我們通過Consumer中的Service去調(diào)用Provider服務的一個代碼,就寫完了,所以相比之下這個代碼呢,這個代碼片段還是比較多的,當然你也可以自己封裝,比如你可以把這些代碼做一個封裝,然后只要根據(jù)給定的參數(shù),直接在你封裝的工具類里直接做拼接了,或者做一些發(fā)送就可以了,你自己回球定義一個工具類,進行封裝就可以了,我們現(xiàn)在把Consumer的Service代碼copy過來,先粘到筆記當中,這一塊大家要認真的看一看,因為我們服務與服務之間的通信,可以說在微服務開發(fā)當中,是非常重要的,因為我們服務和服務之間肯定是要做調(diào)用的,然后我們再來看,這一部分改完了,但是Consumer的Controller還沒有改完我們直接寫個consumer,我們是不是先得把業(yè)務層注入進來@Autowired
private UserService userService;然后我們這里要做的就是調(diào)用userService下的getUsers方法,這個是他的Controller,那么我們的Consumer和Provider寫完以后呢,就可以進行測試了,現(xiàn)在沒有任何服務,我們先把Provider啟動,觀察控制臺,然后我們再去啟動Consumer,那么Consumer也啟動好了,接下來我們是不是就可以訪問Consumer的Controller了,他的端口是多少,他的端口是9091,這個是9091下面的一個consumerlocalhost:9091/consumer這里出了一個異常,我們來看一下是不是拿到了,剛才應該是我們的服務還沒有啟動完畢,那么我們看,現(xiàn)在我們看到的數(shù)據(jù)就是從Consumer當中拿到的,那么Consumer又是從哪里拿到的呢,在他的Service當中,去調(diào)用我們Provider服務當中的接口,在這個接口當中,做了一個數(shù)據(jù)的定義,然后通過Provider將數(shù)據(jù)返回給我們的Consumer,所以我們看到的數(shù)據(jù)就是Provider返回回來的,那么在服務與服務之間調(diào)用的當中呢,大家需要重點了解的,重點注意的就是,LoadBalancerClient這個對象,我們通過這個對象,根據(jù)服務的名稱返回一個實例,我們通過這個實例,是可以拿到服務的IP和端口,然后我們對服務的IP和端口進行一個拼接,變成一個完整的訪問服務的URL,然后我們再通過SpringMVC提供的RestTemplate,就可以去請求我們的服務了,Consumer去請求Provider的案例的一個講解
<?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><!-- 這個插件,可以將應用打包成一個可執(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負載均衡器public List<User> getUsers(){//選擇調(diào)用的服務的名稱//ServiceInstance 封裝了服務的基本信息,如 IP,端口ServiceInstance si = this.loadBalancerClient.choose("springcloud-eureka-provider");//拼接訪問服務的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服务的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 创建consumer服务
- 下一篇: eureka架构图原理