在consumer中调用provider服务

我们已经把Consumer的环境搭建好了,我们也把UserService写好了,我们再来看一下,如何在Consumer的UserService

当中,去调用Provider当中的接口,那么我们要调服务的接口,肯定得知道服务的信息,那么我们在SpringCloud的微服务

当中,如何知道调用服务的基本信息呢,比如服务的IP地址是多少,服务的端口是什么,那么在SpringCloud当中呢,那给我们

提供了一个对象,这个对象叫什么呢,叫LoadBalancerClient,这个对象是什么呢,直接把他定义出来,这个对象是SpringCloud

提供的一个复杂均衡的对象,Ribbon,在SpringCloud当中,是通过Ribbon来完成负载均衡的,那么loadBalancerClient,就是

Ribbon技术下的一个对象,那么至于负载均衡器,所以称之为负载均衡器

private LoadBalancerClient loadBalancerClient;//ribbon负载均衡器

我们在后续中呢,会去讲解他的,那么我们为什么要拿到LoadBalancerClient呢,因为我们通过这个对象,可以取到我们要调用

服务的IP地址和端口,那么他是怎么去找IP地址和端口的呢,就是通过服务的名称,我们的服务不都有一个名称吗,我们provider的,

是不是叫

springcloud-eureka-provider

那么我们现在Consumer的服务,就不能叫跟他相同的名字了,我们应该叫

springcloud-eureka-consumer

我们改过来,也就是说,SpringCloud,在帮我们去查找信息的时候呢,就是通过我们给服务起的名称,然后他会去注册中心里,根据名称

找到这个服务,并且把服务的基本信息,封装到LoadBalancerClient对象当中,然后我们通过这个对象去获取服务的基本信息,我们就可以

拿到服务的IP和端口了,那么在这里我们如何使用loadBalancerClient去获取服务的信息呢,这里我们需要用到一个对象,这个对象

是谁呢,这个对象叫ServiceInstance,然后咱们叫si,然后this.loadBalancerClient,这是咱们上面定义的对象,通过这个对象,

他下面有choose方法,这个choose的方法呢,就是通过我们要查找的接口的名称去做接口的查找,并且返回一个接口的封装对象,

ServiceInstance,那么我们要查找的接口的名称,是不是Provider里面的

springcloud-eureka-provider

所以我们现在给服务其名称的时候不能随便乱起

ServiceInstance si = this.loadBalancerClient.choose("springcloud-eureka-provider");

然后拿到接口的实例,ServiceInstance以后,我们该做什么事呢,其实在这个对象当中,封装了服务的基本信息,如IP,端口,那么

也就意味着我们通过这个对象,可以取到我们服务的IP和端口了,然后大家注意,在SpringCloud当中呢,他对于服务与服务之间

的通信,采用的是URL的形式,所以说我们在这儿,还得拿着服务返回回来的实例,这个对象,去获取我们的服务的IP和端口,

拼成一个URL,所以这里我们还得URL的拼接,拼接访问服务的URL

sb.append("http://").append(si.getHost()).append(":").append(si.getPort()).append("/user");

其实我们说个题外话,我感觉SpringCloud对于服务的调用这一块,相比我们的Dubbo来讲,要复杂一些,因为我们的Dubbo把对象

直接注入进来,@Reference就可以,但是在SpringCloud当中呢,他都是通过URL的方式来访问接口,有点像什么呢,他的这种形式

有点像之前,用过一个Apache的工具,叫HttpClient,跟他有点相似,然后通过StringBuffer去拼接我们的URL,我肯定要拼接

一个HTTP,要通过http协议,

sb.append("http://").append(si.getHost()).append(":").append(si.getPort()).append("/user");

然后接着往后追加,追加什么呢,我们拼的URL是不是应该这样的

http://localhost:9090/user

我们在Provider当中,我们的Provider应该是启动的,我们的启动器改一下,最好叫ConsumerApplication,然后我们来运行这个

Consumer的实例,然后我们刷新,然后注意看Provider9090,这个是不是我们要访问的服务,然后我们看一下里面的Controller,

原来我们通过浏览器地址栏访问,是不是这么访问的,是不是一个叫user的URI

10.40.8.152:9090/user

是不是拿到这个信息了,那么我们现在拼接的URL,应该是这样的,在我们的Consumer当中,要去访问Provider的地址,最后调用接口的

地址是不是应该是这样的,我们是不是要根据这个地址去拼接出来,所以第一个http,第二个我们就不能localhost,因为你这个服务的

IP,它是不确定的,比如我们使用动态IP,我们服务多了,我们总不能一个一个去记IP地址是多少,每一个服务的IP是什么,端口是什么,

所以这块也不用去记住,怎么办呢,我们通过loadBalancerClient返回的ServiceInstance对象里,其实就包含了我们要调用服务的

IP和端口,所以我们之前也说过,我们做微服务开发的时候,不需要你去记住服务的IP和端口的,因为第一个我们服务太多了,

我们也记不住,第二个我们有现成的对象,通过LoadBalancerClient,返回的ServiceInstance,我们就可以去获取服务的基本信息,

关键我们要知道你调用的服务名称是什么,那么这块怎么办呢,正常来讲要拼IP了,我们可以通过si.getHost(),这个Host方法呢,

返回的就是要调用的接口来定义,然后我们还要拼什么,是不是还得拼一个冒号,然后后面是不是还得拼端口,端口si.getPort(),

然后端口拼完了以后,我们的URL就拼完了吗,很显然不是的,后面是不是还有这个信息,这样我们一个访问服务的URL就拼接完毕了,

第一步就已经搞定了,再来看,我们拼完URL以后,是不是要像URL发请求,然后需要一些数据,那么怎么向URL发请求呢,

我们会使用SpringMVC提供的一个对象,RestTemplate,这个大家应该有用过,应该并不陌生,只是封装了一个基于Rest模式的

一个对象,SpringMVC下,那么我们首先要去创建RestTemplate对象

RestTemplate rt = new RestTemplate();

然后你去用它发送请求的时候,是不是要调用Provider的这个Controller,也是会返回一个List,也就是我们现在调用的接口,是有

返回值的,那么我们怎么来处理这个返回值呢,我们来看一下这个代码怎么来编写,首先这里我们要定义一个返回值,有一个叫

ParameterizedTypeReference,我们返回的是什么呢,是一个List,List里面放的是什么,是User,然后这个对象要定义一个名称,

比如叫type,我们这里要去new这个对象,这块我们要注意,这个对象它是一个抽象类,可以看看这个源码

public abstract class ParameterizedTypeReference<T> {

看到了吗,它是一个抽象类,那么抽象类能new吗,跟接口是一样的,你看后面会自动添加一个匿名内部类,作为这个抽象类的一个子类,

那我们把它加上,我们这里也不用加什么方法了,用他里面自带的方法也够用了,然后接下来我们再去定义一个对象,这个对象叫什么呢,

叫ResponseEntity,就是他,这个对象的作用是什么呢,这个对象封装的就是一个返回值的二次封装,这个对象当中,封装了返回值信息,

然后我们返回的是不是一个List,然后这块我们给User,如果用过RestTemplate的同学,应该很熟,这块我们就不细说了,

然后呢response,等于new谁呢,用我们的restTemplate,因为它是发送URL请求的模板对象,有一个exchange方法

ResponseEntity<List<User>> response = rt.exchange(sb.toString(),HttpMethod.GET, null, type);

然后你看exchange方法有这么多,我们随便写一个,这里我们用的是四个参数的,我们来看一下,第一个参数是什么呢,就是你要调用服务的

URL,这个URL我们是不是已经拼接到buffer里面了,所以我们直接sb.toString()就可以了,他要的是一个字符串,第二个是一个method,

method表示什么含义呢,你现在要用什么请求方式去请求他,用get还是post,那我们可以用GET,GET怎么写呢,有一个常量类,是一个枚举,

叫HttpMethod,在这个枚举下呢,有很多在HTTP协议下发送的很多类型,那我们在这里选择GET,第三个参数,你请求有没有参数传递,

那我们现在是没有任何参数的,所以我们这块为空,第三个参数表示请求参数的,然后第四个,responseType,这个 表示什么意思呢,

你返回值的这个对象,用什么类型来包装,在这里我们专门定义了一个返回值类型的对象,ParameterizedTypeReference,这个时候

我们就把这个对象放到里面,然后这个对象,他返回的response,就是封装了我们调用接口后,返回的一个返回值的二次封装的对象,

那我们这里怎么去取呢,很简单,我们现在,我们看一下,我们调用Provider的UserController,是不是返回一个List,那么这样的话,

在我的Consumer当中,他返回的也得是一个List,我这里泛型定义的时候是List,那我们就可以这么写

List<User> list =response.getBody();

然后在这里把list返回,这样我们通过Consumer中的Service去调用Provider服务的一个代码,就写完了,所以相比之下这个代码呢,

这个代码片段还是比较多的,当然你也可以自己封装,比如你可以把这些代码做一个封装,然后只要根据给定的参数,直接在你

封装的工具类里直接做拼接了,或者做一些发送就可以了,你自己回球定义一个工具类,进行封装就可以了,我们现在把

Consumer的Service代码copy过来,先粘到笔记当中,这一块大家要认真的看一看,因为我们服务与服务之间的通信,可以说在

微服务开发当中,是非常重要的,因为我们服务和服务之间肯定是要做调用的,然后我们再来看,这一部分改完了,

但是Consumer的Controller还没有改完


我们直接写个consumer,我们是不是先得把业务层注入进来

@Autowired
private UserService userService;

然后我们这里要做的就是调用userService下的getUsers方法,这个是他的Controller,那么我们的Consumer和Provider写完

以后呢,就可以进行测试了,现在没有任何服务,我们先把Provider启动,观察控制台,然后我们再去启动Consumer,那么

Consumer也启动好了,接下来我们是不是就可以访问Consumer的Controller了,他的端口是多少,他的端口是9091,这个是

9091下面的一个consumer

localhost:9091/consumer

这里出了一个异常,我们来看一下

是不是拿到了,刚才应该是我们的服务还没有启动完毕,那么我们看,现在我们看到的数据就是从Consumer当中拿到的,

那么Consumer又是从哪里拿到的呢,在他的Service当中,去调用我们Provider服务当中的接口,在这个接口当中,做了

一个数据的定义,然后通过Provider将数据返回给我们的Consumer,所以我们看到的数据就是Provider返回回来的,

那么在服务与服务之间调用的当中呢,大家需要重点了解的,重点注意的就是,LoadBalancerClient这个对象,我们通过

这个对象,根据服务的名称返回一个实例,我们通过这个实例,是可以拿到服务的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>
	
	<!-- 这个插件,可以将应用打包成一个可执行的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 {

	@Autowired
	private LoadBalancerClient loadBalancerClient;//ribbon负载均衡器
	
	public List<User> getUsers(){
			//选择调用的服务的名称
		//ServiceInstance 封装了服务的基本信息,如 IP,端口
		ServiceInstance si = this.loadBalancerClient.choose("springcloud-eureka-provider");
		//拼接访问服务的URL
		StringBuffer sb = new StringBuffer();
		//http://localhost:9090/user
		sb.append("http://").append(si.getHost()).append(":").append(si.getPort()).append("/user");
		
		
		//springMVC RestTemplate
		RestTemplate 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 {

	@Autowired
	private 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);
	}
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值