构建SpringCloud 项目初始环境(二)—服务注册中心Nacos

服务注册中心Nacos

一、Nacos注册中心简介

1、背景分析

在微服务中,首先需要面对的问题就是如何查找服务(软件即服务),其次,就是如何在不同的服务之间进行通信?如何更好更方便的管理应用中的每一个服务,如何建立各个服务之间联系的纽带,由此注册中心诞生(例如淘宝网卖家提供服务,买家调用服务)。
市面上常用注册中心有Zookeeper(雅虎Apache),Eureka(Netfix),Nacos(Alibaba),Consul(Google),那他们分别都有什么特点,我们如何进行选型呢?我们主要从社区活跃度,稳定性,功能,性能等方面进行考虑即可.本次微服务的学习,我们选择Nacos,它很好的支持了阿里的双11活动,不仅可以做注册中心,还可以作为配置中心,稳定性和性能都很好.

2、Nacos概述

Nacos(DynamicNaming and Configuration Service)是一个应用于服务注册与发现、配置管理的平台。它孵化于阿里巴巴,成长于十年双十一的洪峰考验,沉淀了简单易用、稳定可靠、性能卓越的核心竞争力。其官网地址如下:

https://nacos.io/zh-cn/docs/quick-start.html

二、构建Nacos服务

1、准备工作

第一:确保你电脑已配置JAVA_HOME环境变量(Nacos启动时需要),例如:

在这里插入图片描述

第二:确保你的MySQL版本为5.7以上(MariaDB10.5以上),例如

在这里插入图片描述
在这里插入图片描述

2、下载与安装

第一步:Nacos下载,可在浏览器直接输入如下地址:
https://github.com/alibaba/nacos/releases
第二步:选择对应版本,直接下载,如图所示:

在这里插入图片描述

第三步:解压Nacos(最好不要解压到中文目录下),其目录结构如下:

在这里插入图片描述

3、初始化配置

第一步:登陆mysql,执行老师发给同学们的sql脚本。例如,我们可以使用mysql自带客户端,在命令行首先登录mysql,然后执行如下指令:
source nacos-mysql.sql

执行成功以后,会创建一个nacos_config数据库,打开数据库会看到一些表,例如:
在这里插入图片描述
说明:在执行此文件时,要求mysql的版本大于5.7版本(MariaDB最好10.5.11),否则会出现如下错误:在这里插入图片描述

第二步:打开/conf/application.properties里打开默认配置,并基于你当前环境配置要连接的数据库,连接数据库时使用的用户名和密码(假如前面有"#"要将其去掉):
### If use MySQL as datasource:
spring.datasource.platform=mysql

### Count of DB:
db.num=1

### Connect URL of DB:
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=root

4、服务启动与访问

第一步:启动Nacos服务

Linux/Unix/Mac启动命令(standalone代表着单机模式运行,非集群模式):

./startup.sh -m standalone

Windows启动命令(standalone代表着单机模式运行,非集群模式):

startup.cmd -m standalone

关闭Nacos Server
Linux:

sh shutdown.sh

Windows:

cmd shutdown.cmd 或 双击 shutdown.cmd 启动
说明:
1)执行执行令时要么配置环境变量,要么直接在nacos/bin目录下去执行.
2)nacos启动时需要本地环境变量中配置了JAVA_HOME(对应jdk的安装目录),
3)一定要确保你连接的数据库(nacos_config)是存在的.
4)假如所有的配置都正确,还连不上,检查一下你有几个数据库(mysql,…)
第二步:访问Nacos服务。

打开浏览器,输入http://localhost:8848/nacos地址,出现如下登陆页面:
在这里插入图片描述
其中,默认账号密码为nacos/nacos.

三、服务注册与调用入门(重点)

在这里插入图片描述

1、业务描述

创建两个项目Module分别为服务提供者和服务消费者,两者都要注册到NacosServer中(这个server本质上就是一个web服务,端口默认为8848),然后服务提供者可以为服务消费者提供远端调用服务(例如支付服务为服务提供方,订单服务为服务消费方),如图所示:
在这里插入图片描述

2、生产者服务创建及注册

第一步:创建服务提供者工程(module名为sca-provider),继承parent工程(01-sca),其pom.xml文件内容如下:
<?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">
	<parent>
		<artifactId>01-sca</artifactId>
		<groupId>com.jt</groupId>
		<version>1.0-SNAPSHOT</version>
	</parent>
	<modelVersion>4.0.0</modelVersion>

	<artifactId>sca-provider</artifactId>

	<dependencies>

		<!--Web服务-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<!--服务的注册和发现(我们要讲服务注册到nacos)-->
		<dependency>
			<groupId>com.alibaba.cloud</groupId>
			<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
		</dependency>
	</dependencies>


</project>
第二步:创建并修改配置文件application.yml(或者application.properties),实现服务注册,关键代码如下:
server:
  port: 8081
spring:
  application:
    name: sca-provider
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #服务注册和发现(默认是注册到这个地址)

注意:服务名不要使用下划线(“_”),应使用横杠(“-”),这是规则。

第三步:创建启动类,并定义处理请求的控制层对象和方法,关键代码如下:
package com.jt;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
public class ProviderApplication  {
	public static void main(String[] args) {
		SpringApplication.run(ProviderApplication.class, args);
	}

	/**定义Controller对象(这个对象在spring mvc中给他的定义是handler),
	 * 基于此对象处理客户端的请求*/
	@RestController
	public class ProviderController {

		//@Value默认读取项目配置文件中配置的内容
		//8080为没有读到server.port的值时,给定的默认值
		@Value("${server.port}")
		private String server;

		//http://localhost:8081/provider/echo/tedu
		@GetMapping(value = "/provider/echo/{msg}")
		public String doEcho(@PathVariable String msg) {
			return "服务端口:"+server+"   Say:Hello Nacos Discovery " + msg;
		}
	}
}
第四步:启动启动类,然后刷先nacos服务,检测是否服务注册成功,如图所示:

在这里插入图片描述

第五步:打开浏览器,输入http://localhost:8081/provider/echo/msa,然后进行访问。

在这里插入图片描述

四、消费者服务发现及调用

第一步:创建服务消费者(module名为sca-consumer),继承parent工程(01-sca),其pom.xml文件内容如下:
<?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">
	<parent>
		<artifactId>01-sca</artifactId>
		<groupId>com.jt</groupId>
		<version>1.0-SNAPSHOT</version>
	</parent>
	<modelVersion>4.0.0</modelVersion>

	<artifactId>sca-consumer</artifactId>

	<dependencies>
		<!--Web服务-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<!--服务的注册和发现(我们要讲服务注册到nacos)-->
		<dependency>
			<groupId>com.alibaba.cloud</groupId>
			<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
		</dependency>

		<!--当基于feign方式进行服务调用时就需要此依赖-->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-openfeign</artifactId>
		</dependency>

	</dependencies>


</project>
第二步:修改配置文件application.yml,关键代码如下:
server:
  port: 8090
spring:
  application:
    name: sca-consumer
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #从哪里去查找服务
第三步:创建启动类并实现服务消费,关键代码如下:
package com.jt;
@SpringBootApplication
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class,args);
    }
   
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
    
    @RestController
    public class ConsumerController{

        @Value("${spring.application.name}")
        private String appName;
        
        @Autowired
        private RestTemplate restTemplate;
        
        @GetMapping("/consumer/doRestEcho1")
        public String doRestEcho01(){
            String url = "http://localhost:8081/provider/echo/"+appName;
            System.out.println("request url:"+url);
           return restTemplate.getForObject(url, String.class);
        }
    }
}
第五步:启动消费者服务,并在浏览器输入http://localhost:8090/consumer/doRestEcho1地址进行访问,假如访问成功会出现,如图所示效果:

在这里插入图片描述

五、服务负载均衡设计及实现(重点)

1、入门案例

一个服务实例可以处理请求是有限的,假如服务实例的并发访问比较大,我们会启动多个服务实例,让这些服务实例采用一定策略均衡(轮询,权重,随机,hash等)的处理并发请求,在Nacos中服务的负载均衡(Nacos客户端负载均衡)是如何应用的?

第一步:修改ConsumerController类,注入LoadBalancerClient对象,并添加doRestLoadBalancerClientEcho方法,然后进行服务访问。

  @Autowired
  private LoadBalancerClient loadBalancerClient;
   
  @GetMapping("/consumer/doRestEcho02")
 public String doRestEcho02(){
     ServiceInstance serviceInstance = loadBalancerClient.choose("sca-provider");
     String url = String.format("http://%s:%s/provider/echo/%s",serviceInstance.getHost(),serviceInstance.getPort(),appName);
     System.out.println("request url:"+url);
     return restTemplate.getForObject(url, String.class);
     }
 }
第二步:打开Idea服务启动配置,如图所示:

在这里插入图片描述

第三步:修改并发运行选项(假如没有找到这个选项我们需要通过搜索引擎基于组合查询的方法,去找到对应的解决方案,例如搜索 idea allow parallel run(允许多次执行),如图所示:

在这里插入图片描述

第四步:修改sca-provider的配置文件端口,分别以8081,8082端口方式进行启动。
server:
  port: 8081
spring:
  application:
    name: sca-provider
  cloud:
    nacos:
      server-addr: localhost:8848

启动成功以后,访问nacos的服务列表,检测服务是否成功注册,如图所示:
在这里插入图片描述

第五步:启动sca-consumer项目模块,打开浏览器,输入如下网址进行反复服务访问:
http://localhost:8090/consumer/doRestEcho02

在这里插入图片描述
这里多个实例并发提供服务的方式为负载均衡,这里的负载均衡实现默认是因为Nacos集成了Ribbon来实现的,Ribbon配合RestTemplate,可以非常容易的实现服务之间的访问。Ribbon是Spring Cloud核心组件之一,它提供的最重要的功能就是客户端的负载均衡(客户端可以采用一定算法,例如轮询访问,访问服务端实例信息),这个功能可以让我们轻松地将面向服务的REST模版请求自动转换成客户端负载均衡方式的服务调用。

2、@LoadBalanced

当使用RestTemplate进行远程服务调用时,假如需要负载均衡,可以在RestTemplate对象构建时,使用@LoadBalanced对构建RestTemplate的方法进行修饰,例如在ConsumerApplication中构建RestTemplate对象:

@Bean
@LoadBalanced
public RestTemplate loadBalancedRestTemplate(){
    return new RestTemplate();
}

在需要RestTemplate实现负载均衡调用的地方进行依赖注入。例如在ConsumerController类中添加loadBalancedRestTemplate属性:

@Autowired
private RestTemplate loadBalancedRestTemplate;

接下来,可以在对应的服务端调用方的方法内,基于RestTemplate借助服务名进行服务调用, 例如:

@GetMapping("/consumer/doRestEcho3")
public String doRestEcho03(){
    String url=String.format("http://%s/provider/echo/%s","sca-provider",appName);
    //向服务提供方发起http请求,获取响应数据
    return loadBalancedRestTemplate.getForObject(
            url,//要请求的服务的地址
            String.class);//String.class为请求服务的响应结果类型
}

RestTemplate在发送请求的时候会被LoadBalancerInterceptor拦截,它的作用就是用于RestTemplate的负载均衡,LoadBalancerInterceptor将负载均衡的核心逻辑交给了loadBalancer,核心代码如下所示(了解):

public ClientHttpResponse intercept(final HttpRequest request, 
    final byte[] body, final ClientHttpRequestExecution execution) throws IOException {
	final URI originalUri = request.getURI();
	String serviceName = originalUri.getHost();
	return this.loadBalancer.execute(serviceName, 
    requestFactory.createRequest(request, body, execution));
}

@LoadBalanced注解是属于Spring,而不是Ribbon的,Spring在初始化容器的时候,如果检测到Bean被@LoadBalanced注解,Spring会为其设置LoadBalancerInterceptor的拦截器。

3、Ribbon负载均衡策略(了解)

基于Ribbon方式的负载均衡,Netflix默认提供了七种负载均衡策略,对于SpringCloud Alibaba解决方案中又提供了NacosRule策略,默认的负载均衡策略是轮训策略。如图所示:
在这里插入图片描述
当系统提供的负载均衡策略不能满足我们需求时,我们还可以基于IRule接口自己定义策略。

4、小节面试分析

@Bean注解的作用?(一般用于配置类内部,描述相关方法,用于告诉spring此方法的返回值要交给spring管理,bean的名字默认为方法名,假如需要指定名字可以@Bean(“bean的名字”),最多的应用场景是整合第三方的资源-对象)

@Autowired注解的作用?(此注解用于描述属性,构造方法,set方法等,用于告诉spring框架,按找一定的规则为属性进行DI操作,默认按属性,方法参数类型查找对应的对象,假如只找到一个,则直接注入,类型多个时还会按照属性名或方法参数名进行值的注入,假如名字也不同,就出报错.)

Nacos中的负责均衡底层是如何实现的?(通过Ribbon实现,Ribbon中定义了一些负载均衡算法,然后基于这些算法从服务实例中获取一个实例为消费方法提供服务)

Ribbon 是什么?(Netflix公司提供的负载均衡客户端,一般应用于服务的消费方法)

Ribbon 可以解决什么问题? (基于负载均衡策略进行服务调用, 所有策略都会实现IRule接口)

Ribbon 内置的负载策略都有哪些?(8种,可以通过查看IRule接口的实现类进行分析)

@LoadBalanced的作用是什么?(描述RestTemplate对象,用于告诉Spring框架,在使用RestTempalte进行服务调用时,这个调用过程会被一个拦截器进行拦截,然后在拦截器内部,启动负载均衡策略。)

我们可以自己定义负载均衡策略吗?(可以,基于IRule接口进行策略定义,也可以参考NacosRule进行实现)

5、三种方式,负载均衡,完整代码

package com.jt;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.Random;

//@EnableFeignClients注解描述启动类时,用于告诉springboot在启动时,
//扫描启动类所在包或子包中的类,假如接口上有@FeignClient注解描述,则对
//这样的接口创建其实现类,在实现类内部帮我们进行远程服务调用
@EnableFeignClients
@SpringBootApplication
public class ConsumerApplication {
	public static void main(String[] args) {
		SpringApplication.run(ConsumerApplication.class, args);
	}


	 /** @Bean 注解用于描述方法,用于告诉spring框架这个方法的返回值交给spring管理,
	 * spring默认会这个方法返回对象起一个bean的名字(key),默认为方法名.当然也可以
	 * 对一个bean的名字进行自定义,例如@Bean("自己定义的名字").
	 * 思考:spring框架中为什么会给出这样的注解,用于描述方法,在方法中构建对象?
	 * 第一:Spring是一个资源整合框架.
	 * 第二:何为资源?(内存中对象)
	 * 第三:所有对象是否都有类型?
	 * 第四:所有对象的类型都是你自己定义的吗?不一定(有自己,有第三方)
	 * 第五:第三方的类,我们能在类上直接添加注解描述吗(例如@Component)?不可以
	 */

	/**创建RestTemplate对象,然后基于此对象进行远程服务调用*/
	@Bean
	public RestTemplate restTemplate(){
		return new RestTemplate();
	}

	@Bean
	@LoadBalanced //这个注解描述RestTemplate对象时,系统底层会对RestTemplate对象的请求进行拦截
	public RestTemplate loadBalanceRestTemplate(){
		return new RestTemplate();
	}

	@RestController
	public class ConsumerController{


		/**
		 * @Autowired注解描述属性时,会告诉spring框架,要优先按属性类型进行对象的查找和注入,假如
		 * 此类型的对象存在多个,此时还会按照属性名进行查找和比对,有相同的则直接注入(DI),没有相同
		 * 的则出错,当然也可以在属性上添加@Qualifier("bean的名字")注解,指定要注入的具体对象
		 */
		@Autowired
		private RestTemplate restTemplate;

		@Autowired
		private RestTemplate loadBalanceRestTemplate;

		//负载均衡客户端对象(基于此对象可以从nacos中获取服务列表,并且可以基于一定的算法
		//从列表中获取一个服务实例)
		@Autowired
		private LoadBalancerClient loadBalancerClient;


		@Value("${spring.application.name}")
		private String appName;

		//负载均衡方式的调用1
		//http://localhost:8090/consumer/doRestEcho1
		@GetMapping("/consumer/doRestEcho1")
		public String doRestEcho1(){
			//手动自己写负载均衡算法(随机调用服务列表中的服务对象)
			//调用谁?sca-provider中的一个url
            String url1="http://localhost:8080/provider/echo/"+appName;
            String url2="http://localhost:8081/provider/echo/"+appName;
            String url3="http://localhost:8082/provider/echo/"+appName;
            String urls[]=new String[]{url1,url2,url3};
            //随机获取一个小于urls数组长度的整数
            int n=new Random().nextInt(urls.length);
            System.out.println("n="+n);
            //如何调用?
            return restTemplate.getForObject(urls[n],String.class);
		}

		//负载均衡方式的调用2
		@GetMapping("/consumer/doRestEcho2")
		public String doRestEcho2(){
			//基于loadBalancerClient方式获取服务实例
			String serviceId="sca-provider";//这个名字要在nacos的服务列表中
			ServiceInstance choose = loadBalancerClient.choose(serviceId);
			String ip=choose.getHost();
			int port=choose.getPort();
			//String url="http://"+ip+":"+port+"/provider/echo/"+appName;
			String url=String.format("http://%s:%s/provider/echo/%s",ip,port,appName);
			return restTemplate.getForObject(url,String.class);
		}

		@GetMapping("/consumer/doRestEcho3")
		public String doRestEcho3(){
			String serviceId="sca-provider";
			String url=String.format("http://%s/provider/echo/%s",serviceId,appName);
			return loadBalanceRestTemplate.getForObject(url,String.class);
		}
	}

}

六、基于Feign的远程服务调用(重点)

1、背景分析

服务消费方基于rest方式请求服务提供方的服务时,一种直接的方式就是自己拼接url,拼接参数然后实现服务调用,但每次服务调用都需要这样拼接,代码量复杂且不易维护,此时Feign诞生。

2、Feign是什么

Feign 是一种声明式Web服务客户端,底层封装了对Rest技术的应用,通过Feign可以简化服务消费方对远程服务提供方法的调用实现。如图所示:
在这里插入图片描述
Feign 最早是由 Netflix 公司进行维护的,后来 Netflix 不再对其进行维护,最终 Feign 由一些社区进行维护,更名为 OpenFeign。

3、Feign应用实践==(掌握)==

第一步:在服务消费方,添加项目依赖(SpringCloud团队基于OpenFeign研发了starter),代码如下:
<!--当基于feign方式进行服务调用时就需要此依赖-->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-openfeign</artifactId>
		</dependency>
第二步:在启动类上添加@EnableFeignClients注解,代码如下:
@EnableFeignClients
@SpringBootApplication
public class ConsumerApplication {}

第三步:定义Http请求API,基于此API借助OpenFeign访问远端服务,代码如下:
@FeignClient(name="sca-provider")//sca-provider为服务提供者名称
interface RemoteProviderService{
    @GetMapping("/provider/echo/{string}")//前提是远端需要有这个服务
    public String echoMessage(@PathVariable("string") String string);
}

其中,@FeignClient描述的接口底层会为其创建实现类。

第四步:创建FeignConsumerController中并添加feign访问,代码如下:
@RestController
@RequestMapping("/consumer/ ")
public class FeignConsumerController {
    @Autowired
    private RemoteProviderService remoteProviderService;
    /**基于feign方式的服务调用*/
    @GetMapping("/echo/{msg}")
    public String doFeignEcho(@PathVariable  String msg){
        //基于feign方式进行远端服务调用(前提是服务必须存在)
        return remoteProviderService.echoMessage(msg);
    }
}

第五步:启动消费者服务,在浏览器中直接通过feign客户端进行访问,如图所示(反复刷新检测其响应结果):
http://localhost:8090/consumer/echo/8091

在这里插入图片描述

4、服务ID问题分析

项目配置文件中的spring.application.name属性值为服务id,服务注册到nacos以后的服务名就是这个id,后续可以基于这个服务id找到具体的服务实例,然后进行调用.
在这里插入图片描述

5、Feign配置进阶实践(调用接口一样),@FeignClient注解名字问题

在这里插入图片描述

一个服务提供方通常会提供很多资源服务,服务消费方基于同一个服务提供方写了很多服务调用接口,此时假如没有指定contextId,服务启动就会失败,例如假如在服务消费方再添加一个如下接口,消费方启动时就会启动失败,例如:

 @FeignClient(name="sca-provider")
 public interface RemoteOtherService {
     @GetMapping("/doSomeThing")
     public String doSomeThing();
}

其启动异常:

The bean 'optimization-user.FeignClientSpecification', defined in null, could not be registered. A bean with that name has already been defined in null and overriding is disabled.

此时我们需要为远程调用服务接口指定一个contextId,作为远程调用服务的唯一标识即可,例如:

@FeignClient(name="sca-provider",contextId="remoteProviderService")//sca-provider为服务提供者名称
interface RemoteProviderService{
    @GetMapping("/provider/echo/{string}")//前提是远端需要有这个服务
    public String echoMessage(@PathVariable("string") String string);
}

6、Feign配置进阶实践(连接、访问超时)

在这里插入图片描述

还有,当我们在进行远程服务调用时,假如调用的服务突然不可用了或者调用过程超时了,怎么办呢?一般服务消费端会给出具体的容错方案,例如:

6.1)方式一:#ribbon方式访问超时配置

在配置文件application.yml中添加如下配置

ribbon:
	ConnectTimeout: 15000   #连接超时(主要是针对网络阻塞)
	ReadTimeout: 30000      #请求处理超时
6.2)方式二:feign方式的服务熔断处理
第一步:定义FallbackFactory接口的实现,代码如下:
package com.cy.service.factory;
/**
 * 基于此对象处理RemoteProviderService接口调用时出现的服务中断,超时等问题
 */
@Component
public class ProviderFallbackFactory
        implements FallbackFactory<RemoteProviderService> {
    /**
     * 此方法会在RemoteProviderService接口服务调用时,出现了异常后执行.
     * @param throwable 用于接收异常
     */
    @Override
    public RemoteProviderService create(Throwable throwable) {
        return (msg)->{
                return "服务维护中";
        };
    }
}
第二步:在Feign访问接口中应用FallbackFactory对象,例如:
@FeignClient(name = "sca-provider", contextId = "remoteProviderService",
             fallbackFactory = ProviderFallbackFactory.class)//sca-provider为nacos中的服务名
public interface RemoteProviderService {
    @GetMapping("/provider/echo/{msg}")
    public String echoMsg(@PathVariable String msg);
}
第三步:在配置文件application.yml中添加如下配置,启动feign方式调用时的服务中断处理机制。
feign:  
  hystrix:
    enabled: true #默认值为false
第四步:在服务提供方对应的方法中添加Thread.sleep(10000)模拟耗时操作,然后启动服务进行访问测试。
http://localhost:8090/consumer/echo/tedu

在这里插入图片描述

7、Feign配置进阶实践(连接、访问超时)

在这里插入图片描述
这张图描述了远程服务调用的几中方式:
第一种:服务比较少,例如就两个服务,一个服务消费,一个服务提供,就不需要注册中心,不需要负载均衡。
第二种:并发比较大,服务服务比较多,我们需要管理服务,就需要注册中心,我们还需要服务间的负载均衡,但代码编写的复杂多相对高一些,我们需要自己获取ip,获取端口,拼接字符串等。
第三种:我们要基于第二种进行代码简化,底层提供了一种拦截器,把基于服务名获取服务实例的过程在拦截器中做了封装,简化了代码的开发.但是加了拦截器多少会在性能少有一点损耗。
第四种方式:主要是从代码结构上做一个挑战,我们前面三种基于RestTemplate进行服务调用,本身属于一种远程服务调用业务,能够将这种业务写到一个业务对象中,Feign方式就诞生了,它主要对代码结构的一种优化。

七、Feign 调用过程分析(了解)

Feign应用过程分析(底层逻辑先了解):
1)通过 @EnableFeignCleints 注解告诉springcloud,启动 Feign Starter 组件。
2) Feign Starter 在项目启动过程中注册全局配置,扫描包下所由@FeignClient注解描述的接口,然后由系统底层创建接口实现类(JDK代理类),并构建类的对象,然后交给spring管理(注册 IOC 容器)。
3) 接口被调用时被动态代理类逻辑拦截,将 @FeignClient 请求信息通过编码器生成 Request对象,基于此对象进行远程过程调用。
4) 请求对象经Ribbon进行负载均衡,挑选出一个健康的 Server 实例(instance)。
5) 通过 Client 携带 Request 调用远端服务返回请求响应。
6) 通过解码器生成 Response 返回客户端,将信息流解析成为接口返回数据。

八、小节面试分析

为什么使用feign?(基于Feign可以更加友好的实现服务调用,简化服务消费方对服务提供方方法的调用)。
@FeignClient注解的作用是什么?(告诉Feign Starter,在项目启动时,为此注解描述的接口创建实现类-代理类)
Feign方式的调用,底层负载均衡是如何实现的?(Ribbon)
@EnableFeignCleints 注解的作用是什么?(描述配置类,例如启动类)

九、总结(Summary)

重难点分析

何为注册中心?(用于记录服务信息的一个web服务,例如淘宝平台,滴滴平台,美团外卖平台,……)
注册中心的核心对象?(服务提供方,服务消费方,注册中心-Registry)
市面上常用注册中心?(Google-Consul,Alibaba-Nacos,…)
微服务架构下项目的构建过程?(聚合工程)
Nacos安装、启动、服务的注册、发现机制以及实现过程?
Feign的基本应用以及底层底层调用原理?

FAQ分析

Nacos是什么,提供了什么特性(服务的注册、发现、配置)?
你为什么会选择Nacos?(活跃度、稳定、性能、学习成本)
Nacos的官网?(nacos.io)
Nacos在github的源码?(github.com/alibaba/nacos)
Nacos在windows环境下安装?(解压即可使用)
Nacos在windows中的的初步配置?(application.properties访问数据库的数据源)
Nacos服务注册的基本过程?(服务启动时发送web请求)
Nacos服务消费的基本过程?(服务启动时获取服务实例,然后调用服务)
Nacos服务负载均衡逻辑及设计实现?(Ribbon)
注册中心的核心数据是什么?(服务的名字和它对应的网络地址)
注册中心中心核心数据的存取为什么会采用读写锁?(底层安全和性能)
Nacos健康检查的方式?(基于心跳包机制进行实现)
Nacos是如何保证高可用的?(重试,本地缓存、集群)
Feign是什么,它的应用是怎样的,feign应用过程中的代理对象是如何创建的(JDK)?
Feign方式的调用过程,其负载均衡是如何实现?(Ribbon)

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AimerDaniil

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值