一、SpringCloud概述

说到SpringCloud,相信大家都不陌生,它主要是用来管理微服务的,说直白有点,它就是基于SpringBoot实现的一套微服务治理工具包,它并不是一个框架,而是一系列框架的集合,管理各个微服务之间的相互协调、相互调用,最终实现用户的价值。
在这里,我觉得我有必要提一下微服务的概念。其实微服务就是一种思想,就是将一个单体项目根据业务的不同从而划分为一个一个的微服务,这些微服务可以独立开发,独立选型(开发语言),独立测试,独立运维,独立部署。微服务之间相互调用,相互协调,最终实现用户的价值。
其实我们知道,用于管理微服务的架构不仅仅只有Springcloud,还有我们比较熟悉的dubbo,它也是用于管理微服务架构的。Springcloud和dubbo最大的区别就是调用的方式不同,SpringCloud使用的RestFul调用方式,而Dubbo使用的RPC远程调用。
前面也说到,Springcloud不是一个框架,而是许多框架的集合,其中极为重要的就是Springcloud的五大神兽
1、Eureka------注册中心
2、ribbon/feign-----负载均衡
3、hystrix ----- 熔断器
4、zuul ------网关
5、统一配置中心
这里有一个Springcloud的示意图,可以参考一下,下面我会一一的讲解Springcloud的五大神兽的作用以及使用

二、五大神兽的概述与使用

在讲解五大神兽之前,我默认大家对SpringBoot都比较熟悉了,因为Springcloud是在SpringBoot的基础上实现的,所有对SpringBoot的熟练度有一定的要求,如果对SpringBoot不熟悉的,建议可以先去看一下关于SpringBoot的相关知识。

1. Eureka
1.1eureka简介
Eureka是Springcloud推荐使用的注册中心,它有什么用呢,它相当于一个注册机,服务提供者,服务消费者,网关等都会将自己信息注册到上面,后面服务消费者就直接从Eureka中去获取服务提供者的信息来进行调用。
示意图:

1.2eureka的单机环境搭建
(1)创建一个普通的maven项目
(2)导入依赖包

在这里插入代码片<!--springboot支持-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId>
</dependency><!--Eureka服务端支持-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

这里的依赖为Eureka的基础依赖。如需要要其他的依赖,请根据具体的业务添加
(3)application.yml配置

server:port: 7001
eureka:instance:hostname: localhostclient:registerWithEureka: false #是否要注册到eurekafetchRegistry: false #表示是否从Eureka Server获取注册信息serviceUrl:defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #单机配置

(4)启动类

@SpringBootApplication
@EnableEurekaServer  //表示Eureka可用
public class EurekaServerApplication_7001 {public static void main(String[] args) {SpringApplication.run(EurekaServerApplication_7001.class);}
}

(5)启动并访问eureka

如果能看到上面的界面,就说明单机版的Eureka的环境已经搭建成功了。
1.2eureka的集群环境搭建
既然有了单机版的eureka,为什么还要搞集群呢?
如果只有一个注册中心服务器,会存在单点故障,所以要集群。
既然是集群,那么毋庸置疑的是可以同时部署多个Euraka,我这里就以两个为例,多个也是一样的
因为我是在本地机器上玩儿的,所有在搭建集群的时候,我还需要做一些处理,就是把等本的ip地址做一下映射,如果不做映射的话,两个eureka的ip地址都是127.0.0.1,测试的时候就很难看错效果。如果是在不同的服务器上部署的话,就不用做映射了,直接用真实ip就可以了
做ip映射的话,只需要修改下面一个地方就可以了:
在我们本地C:\Windows\System32\drivers\etc下面的hosts文件,打开它修改一下就可以了。


下面我们就开始来玩儿erueka的集群
集群的eureka其实和单机版的erueka差不多,pom,主类都是一样的,唯一不同的就是application.yml的配置有点不同
下面是eureka_7001和eureka_7002的配置文件内容
eureka_7001:

server:port: 7001
eureka:instance:hostname: eureka-7001.comclient:registerWithEureka: false #是否要注册到eurekafetchRegistry: false #表示是否从Eureka Server获取注册信息serviceUrl:
#      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #单机配置defaultZone: http://eureka-7002.com:7002/eureka/ #集群配置

eureka_7002:

server:port: 7002
eureka:instance:hostname: eureka-7002.comclient:registerWithEureka: false #是否要注册到eurekafetchRegistry: false #表示是否从Eureka Server获取注册信息serviceUrl:
#      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #单机配置defaultZone: http://eureka-7001.com:7001/eureka/ #集群配置

从上面的两个配置文件内容我们可以看出,就是只有最下面的注册地址不同。**在集群的情况下,配文件中的注册地址的地方,除了不配自己之外,其他的eureka地址都要配上,多个就用“,”隔开即可。**就如上面的代码,我现在只有两个eureka,在eureka_7001中只配置了eureka_7002,相反,在eureka_7002中也只配置了eureka_7001,都没有配置自己。
配置完成之后,可以将两个erueka启动起来,并且访问这两个eureka,你会发现,在任何一个eureka中可以看到其他的eureka,如下图:
eureka_7001

eureka_7002

如果能看到上面的界面,那么eureka的集群环境就搭建好了。
2服务的提供者以及服务消费者的搭建
这里解释一下,服务提供者就是暴露接口的服务,服务消费者就是调用接口的服务
2.1服务的提供者搭建:
(1)创建一个普通的maven项目,名称为user_provider_8001
(2)导入jar包

    <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency><!--eureka客户端支持 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency>

(3)application.yml的配置

server:port: 8001
spring:application:name: USER-PROVIDER #不要使用下划线#配置数据库信息datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf8username: xxxxxxpassword: xxxxxx#将服务提供者注册到注册中心
eureka:client:service-url:
#      defaultZone: http://localhost:7001/eureka #单机注册defaultZone: http://eureka-7001.com:7001/eureka,http://eureka-7002.com:7002/eureka #集群注册instance:prefer-ip-address: true #显示客户端真实ip
logging:  #显示日志level:cn.itsource.springcloud.mapper: debug

填写注册地址时,有多少个eureka,就要填写多少个注册地址
(4)启动类

@SpringBootApplication
@EnableEurekaClient  //表示为Eureka客户端
public class UserProviderApplication8001 {public static void main(String[] args) {SpringApplication.run(UserProviderApplication8001.class);}
}

启动类中最重要的@EnableEurekaClient这个注解
当然,既然erueka可以做集群部署多个,服务提供者同样是可以做集群的,同样的一个服务提工作也可以同时部署多份在服务其上面,可以解决单点故障的问题,也可以满足负载均衡调用,负载均衡调用我们在后面会讲到,在这里就不做概述。
将上面的配置都配置好后,将erueka启动起来,然后将服务提供和也启动起来,访问eureka:

如果能看到这个界面,就说明服务提供者搭建好了。
上面之所以显示了8001和8002,是因为我启动两个服务提供者。
2.2服务的消费者搭建:
我们先来玩儿一个比较老的技术,就是不通过Eureka,直接进行远程调用,虽然这玩意儿比较老,还是可以记录一下,以防以后需要维护一些老的使用了远程调用的,但是并没有使用springcloud的项目,就可以用的上了。
我们先来创建服务的消费者,因为这里我们不是Springcloud的eureka来注册,所以现在所建立的服务消费者其实就是一个普普通通的Springboot项目,如下:
(1)创建一个普通的maven项目,名称为user_consumer_9001
(2)导入jar包

  <!--springboot支持--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency>

什么依赖都不要,就只要这两个,但是有业务上的依赖,该加的还是得加
(3)application.yml的配置

server:port: 9001
spring:application:name: USER-CONSUMER#配置数据库信息datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf8username: xxxxxpassword: xxxxx

(4)启动类

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

现在服务的消费者创建好了,服务的提供者上面也创建好了,controller里面的业务代码请自行编写。下面我们就来实现不通过eureka的方式来进行远程调用。
我们可以使用RestTemplate来进行远程调用,只需要两部,很简单,步骤如下:
(1)在服务的消费者下面自定义一个类,这类的一定要和入口类平级或者在入口类的子包里面,因为启动入口类在启动的时候会自动的去扫描我们写的这个自定义类。自定义类的类名可以随便写,但是里面的内容是固定的,代码如下:

@Configuration  //表示交给spring管理,从而创建一个ConfigBean的bean
public class ConfigBean {@Beanpublic RestTemplate getTemplate(){return new RestTemplate();}
}

注意:@Configuration注解不能少,如果不加这个注解,Spring是管理不到这个类的。
从代码中我们可以看到,其实就是获取一个RestTemplate的实例。
现在自定义类编写完毕,接下来就可以在消费者的Controller中调用服务了,代码如下:

@RestController
@RequestMapping("/consumer")
public class UserController {/*** 通过原始的方式,即通过RestTemplate来进行远程调用,不通过Eureka*///多个方法调用只需改一处就okpublic static  final String URL_PREFIX = "http://localhost:8001";@Autowiredprivate RestTemplate restTemplate;@GetMapping("/getUserById")public User getUserById(@RequestParam Integer id){User user = restTemplate.getForObject(URL_PREFIX+"/provider/getUserById?id="+id, User.class);return user;}
}

稍微的解释一下上面的代码,就是注入一个RsetTemplate,然后通过调用getForObject方法来获取数据。getForObject方法中有两个参数,第一个参数是url,即需要调用服务提供者接口的url,第二个参数返回值的class
代码编写完成只用,就可以启动服务提供者和服务消费者。直接访问服务消费者的接口地址,就可以获取到服务提供者中的数据了。
以上这种方式是没有通过Springcloud的eureka来实现的,下面,我们开始讲解通过eureka来实现远程调用,即五大神兽之二的负债均衡调用ribbon/feign的使用
3、负债均衡ribbon/feign
为了提供并发量,有时同一个服务提供者可以部署多个。这个客户端在调用时要根据一定的负责均衡策略完成负载调用。
Springcloud的负载均衡有两种技术,ribbon和feign。下面来一一的讲解
3.1Ribbon
其实ribbon的底层还是使用的RestTemplate来实现的。
服务的提供者不需要做任何的改变,就使用我们上面创建好的就行了,我们只需要改变服务的消费者就可以了,现在我们重新来创建一个消费者
直接搞代码:
(1)创建一个普通的maven项目,名称为user_consumer_9002
(2)导入依赖

 <!--springboot支持--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency><!--eureka客户端,服务消费者也要从注册中心获取可用服务列表--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><!--客户端负载均衡实现 ribbon--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-ribbon</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-config</artifactId></dependency>

每一个依赖都是有注释的
(3)application.yml的配置:

server:port: 9002
spring:#配置数据库信息datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf8username: xxxxxpassword: xxxxx
eureka:client:registerWithEureka: false #不注册到Eureka,不在注册中心显示service-url:#defaultZone: http://localhost:7001/eureka  #单机配置defaultZone: http://eureka-7001.com:7001/eureka,http://eureka-7002.com:7002/eureka #集群配置

因为现在要通过eureka来进行远程调用,那么服务的消费者也需要注册到eureka中
(4)启动类

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

(5)进行负载均衡调用
这时需要服务消费者中自定一个类,类名可以随便写,但是位置必须和启动类平级或者在启动类的子包里面。类中的代码如下:

@Configuration   //表示将该类交给Spring管理
public class ConfigBean {@Bean@LoadBalanced  //开启负载均衡public RestTemplate getRestTemplate(){return new RestTemplate();}
//    修改负载均衡策略,默认是轮询@Beanpublic IRule myRule(){return new RandomRule();//通过随机算法替代轮询}
}

咋眼一看,怎么和之前的RestTemplate的那个配置类那么相似呢。没错,是相似但不相同,仔细一看,在getRestTemplate方法上多了一个@LoadBalanced 注解,这个注解就是用来开启负载均衡的。
下面还有一个方法myRule,这个方法的作用就是对负载均衡的策略进行设置的,默认的轮询调用。还有几种策略,可以去网上查一下,这里就不做过多的讲解。
配置类编写完毕之后哦,下面就可以在消费者的Controller中进行远程调用了,业务调用代码如下:

@RestController
@RequestMapping("/consumer")
public class UserController {/*** 通过Ribbon来实现负载均衡调用*///多个方法调用只需改一处就okpublic static  final String URL_PREFIX = "http://USER-PROVIDER";@Autowiredprivate RestTemplate restTemplate;@GetMapping("/getUserById")public User getUserById(@RequestParam Integer id){User user = restTemplate.getForObject(URL_PREFIX + "/provider/getUserById?id=" + id, User.class);return user;}
}

因为现在是通过SpringCloud的ribbon来进行调用的,所有就和上面只用使用RestTemplate调用有所不同。从上面的代码可以看到,服务提供者的接口地址已经不是使用的ip加端口号了,因为是负载均衡调用,同一个服务提供者可能会部署多份,但是多个相同的服务提供者的服务名是一样的,所以这里就需要拼接服务提供者的服务名和接口名来进行调用。
现在代码就编写完了,这是启动eureka,服务消费者,服务提供者。最后访问服务消费者的接口地址,就能访问到服务提供者的数据了。这里我就不演示了,自己可以去测试一下。
现在功能虽然是实现了,但是还有一个问题,就是在调用服务提供者接口的时候,服务提供者需要的参数都是拼在url后面的,如果参数个数少,还可以接受,如果参数有100个乃至更多,就很恶心了,所有我们一般不用ribbon来做负载均衡,我们会选择使用SpringCloud的第二种负载均衡技术feign来实现,当然,这还是要根据业务的需求来定。下面我们来看看feign的具体使用。
3.2feign
上面我们已经说了Ribbon的缺点就是在参数太多的时候拼接参数时很不爽,如果使用feign的话,就不会出现这个问题了,因为feign调用的时候不是通过拼接url和参数来实现的,而是通过接口的方式来实现的,这样的话不管服务提供者需要多少参数,消费者在调用的时候直接将需要的参数传过去就完事儿。下面直接搞代码,我们需要重新新建一个服务的消费者user_consumer_9003,方便测试。
(1)创建一个普通的maven项目user_consumer_9003
(2)导入jar包

  <!--springboot支持--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency><!--eureka客户端,服务消费者也要从注册中心获取可用服务列表--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><!--feign的支持--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency>

(3)aplication.yml配置

server:port: 9003
eureka:client:registerWithEureka: false #不注册到Eureka,不在注册中心显示service-url:#defaultZone: http://localhost:7001/eurekadefaultZone: http://eureka-7001.com:7001/eureka,http://eureka-7002.com:7002/eureka
spring:#配置数据库信息datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf8username: xxxxxpassword: xxxxx

(4)入口类

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(basePackages = {"cn.itsource.springcloud"})
public class UserConsumerFeignApplication_9003 {public static void main(String[] args) {SpringApplication.run(UserConsumerFeignApplication_9003.class);}
}

因为使用feign的方式来进行调用时,也需要在消费者新建一个feign的接口,所有我们需要在入口类上面打上@EnableFeignClients注解,并且在后面配置feign接口的全包名。
下面新建一个feign接口,该接口名可以随便写,但是位置必须和入口类平级或者在入口类的子包里面。
接口代码:

@FeignClient("USER-PROVIDER")
public interface UserFeign {@GetMapping("/provider/getAllUsers")List<User> getAllUsers();
}

注意:
1、@FeignClient注解一定不要忘记,后面需要配置需要调用的服务提供者的服务名。
2、接口的方法名和返回值类型需要和需要调用的接口的方法名和返回值类型一致,请求方式也必须一致,请求路径为需要调用的服务提供者接口地址。
3、如果接口需要参数,那么参数前面需要加上@RequestParam注解,并且括号类需要写入参数名称,如:User getUserById(@RequestParam(“id”) Integer id);这一点要切记啊,因为本人在这个坑里面跳了几个小时,就因为括号里面没有写参数名称

接口写好以后,接下来就可以在Controller中调用服务了
代码如下:

@RestController
@RequestMapping("/consumer")
public class UserController {@Autowiredprivate UserFeign userFeign;@GetMapping("/getAllUsers")public List<User> getAllUsers() {List<User> allUsers = userFeign.getAllUsers();return allUsers;}
}

就是注入我们刚才写的那个feign接口,然后使用注入进来的实例来调用接口中的方法,这样直接访问服务消费者的接口,就可以获得服务提供者的数据了。
4.熔断器Hystrix
在理想状态下,一个应用依赖的服务都是健康可用的,我们可以正常的处理所有的请求。如下图:

但是 当某一个服务出现延迟时,所有的请求都阻塞在依赖的服务Dependency I ,当依赖I 阻塞时,大多数服务器的线程池就出现阻塞(BLOCK),影响整个线上服务的稳定性。在复杂的分布式架构的应用程序有很多的依赖,都会不可避免地在某些时候失败。高并发的依赖失败时如果没有隔离措施,当前应用服务就有被拖垮的风险,如下图:

对于上面的问题,我们就需要对依赖做隔离,Hystrix就是处理依赖隔离的框架,同时也是可以帮我们做依赖服务的治理和监控.。
4.1Hystrix简介
Hystrix是国外知名的视频网站Netflix所开源的非常流行的高可用架构框架。Hystrix能够完美的解决分布式系统架构中打造高可用服务面临的一系列技术难题。
Hystrix是保证微服务群健壮框架,做了隔离,熔断,降级等操作.最终达到不会由于某一个服务出问题而导致雪崩现象,让整体群死掉.
Hystrix “豪猪”,具有自我保护的能力。hystrix 通过如下机制来解决雪崩效应问题。
**资源隔离(限流):**包括线程池隔离和信号量隔离,限制调用分布式服务的资源使用,某一个调用的服务出现问题不会影响其他服务调用。
**融断:**当失败率达到阀值自动触发降级(如因网络故障/超时造成的失败率高),熔断器触发的快速失败会进行快速恢复。
**降级机制:**超时降级、资源不足时(线程或信号量)降级,降级后可以配合降级接口返回托底数据。
**缓存:**提供了请求缓存、请求合并实现。
4.2服务的熔断:
正常情况下,断路器处于关闭状态,如果调用持续出错或者超时,电路被打开进入熔断状态(Open),后续一段时间内的所有调用都会被拒绝,一段时间以后,保护器会尝试进入半熔断状态(Half-Open),允许少量请求进来尝试,如果调用仍然失败,则回到熔断状态,如果调用成功,则回到电路闭合状态。
熔断的参数配置
Hystrix提供了如下的几个关键参数,来对一个熔断器进行配置:
circuitBreaker.requestVolumeThreshold //滑动窗口的大小,默认为20
circuitBreaker.sleepWindowInMilliseconds //过多长时间,熔断器再次检测是否开启,默认为5000,即5s钟
circuitBreaker.errorThresholdPercentage //错误率,默认50%
3个参数放在一起,所表达的意思就是:
每当20个请求中,有50%失败时,熔断器就会打开,此时再调用此服务,将会直接返回失败,不再调远程服务。直到5s钟之后,重新检测该触发条件,判断是否把熔断器关闭,或者继续打开。
4.3Hystrix的实现
我们通过上面的知识已经知道,服务的负载均衡调用有两种方式,ribbon和feign,如果要使用Hystrix来实现熔断,就只能在ribbon下面使用。feign有自己的熔断机制,但是底层还是使用的Hystrix。下面就来学习一下分别在ribbon和feign下面如何来实现熔断功能吧
4.3.1在ribbon下面实现熔断机制
在ribbon下面实现熔断机制的话,我们就需要在服务的提供者上面做配置,然后在接口后面定义一个多托底方法,当真正的接口调用失败的时候,就会自动的调用这个托底方法,从何获取托底数据。下面我们通过代码来实现一波:
(1)创建一个服务的消费者和一个服务提供者。服务的消费者就可以使用我们上面已经集成了ribbon的user_consumer_9002这个项目即可,只要创建一个普通的Maven项目来作为服务的提供者,名为user_provider_hystrix_8003
(3)application.yml文件的配置

server:port: 8003
spring:application:name: USER-PROVIDER #不要使用下划线#配置数据库信息datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf8username: xxxxxxpassword: xxxxxx#将服务提供者注册到注册中心
eureka:client:service-url:
#      defaultZone: http://localhost:7001/eureka #告诉服务提供者要把服务注册到哪儿defaultZone: http://eureka-7001.com:7001/eureka,http://eureka-7002.com:7002/eureka #告诉服务提供者要把服务注册到哪儿instance:prefer-ip-address: true #显示客户端真实ip
logging:level:cn.itsource.springcloud.mapper: debug

(3)导入jar包

  <!--        公共的依赖--><dependency><groupId>cn.itsource.springcloud</groupId><artifactId>user_common</artifactId><version>1.0-SNAPSHOT</version></dependency><!--        SpringBoot的基本配置--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency><!--eureka客户端支持 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><!--断路器--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix</artifactId></dependency>

(4)入口类

@SpringBootApplication
@EnableEurekaClient
@EnableHystrix //支持熔断器
public class UserProviderHystrixApplication_8003 {public static void main(String[] args) {SpringApplication.run(UserProviderHystrixApplication_8003.class);}
}

(5)只需要在服务提提供者的controller中的方法下面自定义一个方法即可,代码如下:

@RestController
@RequestMapping("/provider")
public class UserController {@Autowiredprivate UserMapper userMapper;@GetMapping("/getUserById")@HystrixCommand(fallbackMethod = "failGet")public User getUserById(@RequestParam Integer id){User user = userMapper.selectById(id);return user;}//    托底方法public User failGet(Integer id){User user = new User();user.setId(new Long(id));user.setName("请联系管理员");return user;}
}

需要强调的是,在接口上面方法上面需要添加一个@HystrixCommand注解,后面需要配置上下面托底方法的方法名。
对于托底方法,参数必须和接口的参数保持一致

4.3.2在feign下面实现熔断机制
从上面ribbon的熔断实现上可以看出,虽然实现了熔断,但是又一个问题,那就是如果服务提供者的controller中的接口方法太多,如果每一个接口方法都要对应一个托底方法的话,controller中的代码就会要边写大量的代码,不仅可读性不好,并且维护性也不好
为了解决riibbon实现熔断时的不足,我们就可以使用feign来实现熔断,刚才说过,feign有一套自己的熔断机制,虽然底层也是通过Hystrix来实现的,但是我们不用直接去使用Hystrix。
feign实现熔断机制的原理其实就是使用spring面向切面编程,为feign的接口创建一个代理对象,完成对服务调用,当发现熔断后就调用同名托底方法.
使用feign来实现熔断机制,我们需要在服务的消费方做配置,代码如下:
(1)创建一个新的服务消费者,名称为user_consumer_feign_hystrix_9004
(2)导入jar包

 <dependency><groupId>cn.itsource.springcloud</groupId><artifactId>user_common</artifactId><version>1.0-SNAPSHOT</version></dependency><!--springboot支持--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency><!--eureka客户端,服务消费者也要从注册中心获取可用服务列表--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><!--feign的支持--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency></dependencies>

(3)application.yml文件的配置

server:port: 9004
eureka:client:registerWithEureka: false #不注册到Eureka,不在注册中心显示service-url:#defaultZone: http://localhost:7001/eurekadefaultZone: http://eureka-7001.com:7001/eureka,http://eureka-7002.com:7002/eureka#开启熔断器支持以及设置超时时间
feign:hystrix:enabled: true #开启熔断支持client:config:remote-service:           #服务名,填写default为所有服务connectTimeout: 3000readTimeout: 3000
hystrix:command:default:execution:isolation:thread:timeoutInMilliseconds: 3000
spring:#配置数据库信息datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf8username: rootpassword: root

使用feign实现熔断时,需要在配置文件中加入开启熔断器支持以及设置超时时间
(4)入口类

@SpringBootApplication(scanBasePackages ="cn.itsource.springcloud")
@EnableEurekaClient
@EnableFeignClients(basePackages = {"cn.itsource.springcloud"})
public class UserConsumerFeignHystrixApplication_9004 {public static void main(String[] args) {SpringApplication.run(UserConsumerFeignHystrixApplication_9004.class);}
}

(5)添加feign的配置接口
在入口类平级或者子包里面添加一个feign的配置类

@FeignClient(value = "USER-PROVIDER",fallbackFactory = UserFeignHystrixFallbackFactory.class)
public interface UserFeign {@GetMapping("/provider/getUserById")User getUserById(@RequestParam("id") Integer id);@GetMapping("/provider/getUser")User getUser();
}

这个配置类其实和上面通过feign来做负载均衡的配置类差不多,不过有一点不同,那就是在@FeignClient注解后面不仅要配置服务提供者的服务名,还需要配置我们即将要创建的托底代理类的class.
(6)创建托底代理类
此类需要实现一个FallbackFactory接口,泛型就为上面创建的那个配置类。并且这个托底代理类的类名后半部分需要用FallbackFactory结尾,前面可以随便写。代码如下:

@Component
public class UserFeignHystrixFallbackFactory implements FallbackFactory<UserFeign> {public UserFeign create(Throwable throwable) {return new UserFeign() {public User getUserById(Integer id) {User user = new User();user.setId(new Long(id));user.setName("出问题了,请联系管理员");return user;}};}
}

这个代理类需要做一下解释:
1、当我们实现了FallbackFactory接口时,会有一个实现方法,返回值就是我们编写的那个配置类,那么我们在方法里面就直接new一个配置类,然后在new的那个配置类里面写我们的托底业务即可
2、托底代理类上面的@Component一定不要忘记加上

代码编写完之后,我们就可进行测试了,当调用某一个配置接口中的某个方法失败后,就会到托底代理类里面去找和所调用的方法相同方法名的托底方法,从而返回托底数据
可以通过关闭服务提供者或者是在提供者上面打断点来测试得到结果
5、ZUUL路由网关

微服务架构体系中,通常一个业务系统会有很多的微服务,上面开始也说过,微服务的好处自已就是可以自由选型,不同的服务可以使用不同的语言来开发,但是问题来了, 只有所用的语言里面用到了Spring框架,才能注册到Springcloud的eureka中去进行远程调用,但是如果某一个服务所用的开发语言是C++,或者是andrio,又或者是python,这些语言压根儿和Spring没有什么关系,那就不能往eureka上面进行注册。那如果真是这样,是不是就没法进行远程调用了呢。其实不是的,这是我们的zuul路由网关就派上用场了。
当所有的服务都是使用java语言来开发的话,就可以不用考虑zuul网关这个东西了,因为它们都可以直接注册到eureka中来进行远程调用。
当选用和Spring没有关系的语言来开发服务,虽然不能直接往eureka上注册,但是我们可以将zuul注册到eureka上面,然后这些服务就可以通过zuul来转发请求,从而调用服务。
所以zuul最大的一个作用就是可以统一入口,所有的服务消费者都可以通过zuul来实现远程调用。而且zuul的内部是已经封装好负载均衡的,只要通过zuul来进行远程调用,默认就会使用负载均衡调用。
下面就来实现一波代码,代码如下:
(1)创建一个新工程,名为zuul_gateway_9527
(2)导入jar包

  <!--        SpringBoot的基本配置--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency><!--eureka客户端支持 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency>
<!--网关的依赖--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-zuul</artifactId></dependency>

(3)application.yal文件的配置

server:port: 9527
spring:application:name: MICROSERVICE-ZUUL-GATEWAY
eureka:client:service-url:defaultZone: http://localhost:7001/eurekainstance:instance-id: gateway-9527.com   #在注册中心显示的名字prefer-ip-address: true  #是否显示ip
zuul:routes:myUser.serviceId: user-provider  #服务提供者的服务名myUser.path: /user/**  #所有以user开头的访问地址都将user映射到user-provider,防止服务名暴露ignored-services: "*"    #此配置的作用是限制所有的myUer.serviceId都不能访问,只有用myUser.path才能访问。保证安全prefix: /services  #可加可不加,主要作用就是限制在访问路径前面必须加想这段内容,保证访问更加安全。

该配置文件最重要的地方就是zuul下面的这一坨配置,解释一下:
1、 myUser.serviceId后面配置的是服务提供者的服务名,因为zuul是做了负载均衡调用的,负载均衡调用是通过服务提供者的服务名来确定服务的
2、myUser.path: /user/**:所有调用时需要通过上面所配置的服务名打头的接口地址,都可以用user来替换打头进行调用,user会直接映射到user-provider上面。这么可以使得服务名不会暴露
3、ignored-services: “*”,做了这个配置的话,如果是用服务名打头的url是访问不了的,只能通过myUser.path后面所配置的形式进行调用,可以保证更加的安全
4、prefix: /services,前缀,就是在调用的时候,必须在url的最前面加上所配置的内容才能进行正常访问。
(4)入口类

@SpringBootApplication
@EnableZuulProxy  //表示开启网关
public class ZuulGatewayApplication_9527 {public static void main(String[] args) {SpringApplication.run(ZuulGatewayApplication_9527.class);}
}

@EnableZuulProxy一定不要忘记加上,这个表示开启网关
将以上的四部配置完毕后就可以进行测试了。
这里需要提一点,上面也提到过,如果所有的服务都是使用java开发的话,那么就可以直接往eureka中进行注册来进行远程调用,虽然也可以通过zuul来进行调用,但是通过zuul调用会多一次请求的转发,调用会有一点的延时。如果其中有些服务是通过C++等一些与Spring无关的语言开发的,又要调用通过java开发的服务提供者的接口,那么就需要用到Zuul。
其实zuul路由网关的作用远不止只用来做入口,它还可以做登录拦截等其他操作,只是本人值玩儿了这一个功能,这里就只记录了这一个,等后面玩儿了其他的再回来添加。大家也可以上ZUUL的官网进行学习更全面的知识。
6、统一配置中心
在分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件。在Spring Cloud中,有分布式配置中心组件spring cloud config ,它支持配置服务放在配置服务的内存中(即本地),也支持放在远程Git仓库中。在spring cloud config 组件中,分两个角色,一是config server,二是config client。如下图:

那么这个统一配置中心有什么作用呢?
它的作用大概总结一下,有一下5点:
1、集中管理配置文件
2、不同环境不同配置,动态化的更新配置,分环境部署,如dev/test/prod/beta/release
3、运行期间动态调整配置,不在需要在每个服务部署的机器上编写配置文件,服务会向配置中心统一拉取配置信息来配置自己的信息
4、当配置发生变动时,服务不需要重新启动即可感知到配置文件的变化并应用新的配置文件
统一配置中心推荐和gitHub集成使用
下面测试代码来一波:
首先需要在github上传一个配置文件,这是我的github上的文件,大家可以自己在自己的github上上传一份来进行测试

服务端:
(1)创建一个项目
(2)导入jar包

<dependencies><!--springboot支持--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency><!--eureka客户端--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><!--配置中心支持--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-config-server</artifactId></dependency>
</dependencies>

(3)application.yml配置文件

server:port: 1299
eureka:client:service-url:defaultZone: http://localhost:7001/eurekainstance:prefer-ip-address: true
spring:application:name: spring-cloud-config-servercloud:config:server:git:uri: 配置文件在github上的git地址username:git的用户名password: git的密码

(4)启动类

@SpringBootApplication
@EnableEurekaClient //加入注册中心
@EnableConfigServer //启用配置服务端
public class ConfigServerApplication_1299 {public static void main(String[] args) {SpringApplication.run(ConfigServerApplication_1299.class);}
}

配置完毕后,可以通过http://localhost:1299/application-user/test来进行测试,改地址表示找到 application-user这个项目profiles为test的文件
客户端的配置(修改上面任何一个服务消费者或者服务提供者即可):
(1)创建一个maven项目,名称为config_client_3355
(2)导入jar包

<!--配置中心支持--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-config</artifactId></dependency>

(3)准备yml配置文件
使用bootstrap.yml,因为bootstrap.yml是全局的,application.yml是局部的,我们使用全局的

spring:cloud:config:name: application-user #github上面名称profile: test #环境label: master #分支uri: http://127.0.0.1:1299 #配置服务器
eureka:client:service-url:defaultZone: http://localhost:7001/eureka  #告诉服务提供者要把服务注册到哪儿 #单机环境instance:prefer-ip-address: true #显示客户端真实ip

(4)测试,启动eureka,服务端和客户端,看idea的控制台显示的端口,以及eureka上面的注册的名字

这里要说一下,虽然可以将服务的配置放在github上面进行统一管理,但是eureka和服务端的配置文件还是要在项目里面配置,不能放在github上面进行统一配置,因为需要服务端启动起来后,客户端才能通过服务端到github上去获取配置信息。所以服务端的配置文件不能放在gitHub上进行管理。
同理,服务端和客户端首先需要注册到eureka上面才能进行调用,所以要启动服务端和客户端,就必须先要启动eureka,所以eureka的配置文件也不能放在github上面进行管理。
以上就是本人学习SpringCloud微服务架构的笔记,如有不足之处,还望博友指教

《SpringCloud微服务架构》学习笔记相关推荐

  1. 第二行代码学习笔记——第六章:数据储存全方案——详解持久化技术

    本章要点 任何一个应用程序,总是不停的和数据打交道. 瞬时数据:指储存在内存当中,有可能因为程序关闭或其他原因导致内存被回收而丢失的数据. 数据持久化技术,为了解决关键性数据的丢失. 6.1 持久化技 ...

  2. 第一行代码学习笔记第二章——探究活动

    知识点目录 2.1 活动是什么 2.2 活动的基本用法 2.2.1 手动创建活动 2.2.2 创建和加载布局 2.2.3 在AndroidManifest文件中注册 2.2.4 在活动中使用Toast ...

  3. 第一行代码学习笔记第八章——运用手机多媒体

    知识点目录 8.1 将程序运行到手机上 8.2 使用通知 * 8.2.1 通知的基本使用 * 8.2.2 通知的进阶技巧 * 8.2.3 通知的高级功能 8.3 调用摄像头和相册 * 8.3.1 调用 ...

  4. 第一行代码学习笔记第六章——详解持久化技术

    知识点目录 6.1 持久化技术简介 6.2 文件存储 * 6.2.1 将数据存储到文件中 * 6.2.2 从文件中读取数据 6.3 SharedPreferences存储 * 6.3.1 将数据存储到 ...

  5. 第一行代码学习笔记第三章——UI开发的点点滴滴

    知识点目录 3.1 如何编写程序界面 3.2 常用控件的使用方法 * 3.2.1 TextView * 3.2.2 Button * 3.2.3 EditText * 3.2.4 ImageView ...

  6. 第一行代码学习笔记第十章——探究服务

    知识点目录 10.1 服务是什么 10.2 Android多线程编程 * 10.2.1 线程的基本用法 * 10.2.2 在子线程中更新UI * 10.2.3 解析异步消息处理机制 * 10.2.4 ...

  7. 第一行代码学习笔记第七章——探究内容提供器

    知识点目录 7.1 内容提供器简介 7.2 运行权限 * 7.2.1 Android权限机制详解 * 7.2.2 在程序运行时申请权限 7.3 访问其他程序中的数据 * 7.3.1 ContentRe ...

  8. 第一行代码学习笔记第五章——详解广播机制

    知识点目录 5.1 广播机制 5.2 接收系统广播 * 5.2.1 动态注册监听网络变化 * 5.2.2 静态注册实现开机广播 5.3 发送自定义广播 * 5.3.1 发送标准广播 * 5.3.2 发 ...

  9. 第一行代码学习笔记第九章——使用网络技术

    知识点目录 9.1 WebView的用法 9.2 使用HTTP协议访问网络 * 9.2.1 使用HttpURLConnection * 9.2.2 使用OkHttp 9.3 解析XML格式数据 * 9 ...

  10. 安卓教程----第一行代码学习笔记

    安卓概述 系统架构 Linux内核层,还包括各种底层驱动,如相机驱动.电源驱动等 系统运行库层,包含一些c/c++的库,如浏览器内核webkit.SQLlite.3D绘图openGL.用于java运行 ...

最新文章

  1. 判断 std map 中是否有 key
  2. [How TO]-ubuntu下安装selenium
  3. 【opencv4】opencv视频教程 C++ 7、手动调整图像亮度与对比度 g(i, j) = αf(i, j) + β(点操作与邻域操作概念)
  4. ProtoBuf在使用protoc进行编译时提示: Required fields are not allowed in proto3
  5. struts2中拦截器的使用
  6. Linux驱动(8)--内核编译与配置
  7. html 3d坐标,HTML3D
  8. Java调用OpenDDS(2)-理解OpenDDS自带的Messager示例
  9. notepad黑色主题
  10. Java字符流拷贝/复制文本文件,字节流拷贝文本文件乱码,很经典简便
  11. 【java】井字棋游戏 多人版哦
  12. Android 中光线传感器的使用详解
  13. 浏览器打开本地exe
  14. java获取GET和POST请求参数
  15. php正则匹配中文、汉字
  16. matlab gui更新结构体,Matlab GUI教程0x5 -handles结构体用法简介
  17. 【AGM】《风色幻想:纷争—luca篇》角色调整版
  18. 中国移动:持续引领5G后续标准制订
  19. 基于FFmpeg的视频播放器之十六:完结
  20. 18万美元offer!ChatGPT通过谷歌L3入职测试,人类码农危?

热门文章

  1. 【C语言 MOOC】程序设计入门_C语言(翁恺)
  2. 办公室可以挂画吗?挂什么样的画好?
  3. JMeter(1) 安装与配置
  4. jinja2简单介绍
  5. Vue学习笔记 —— 路径引入
  6. 《现代工业经济和信息化》学术刊约稿函
  7. 裁员还不够,GitHub 要求全员转 Teams 惹开发者吐槽!
  8. css 面包屑 30个字节,纯CSS3编写的面包屑导航收集
  9. Linux 非root用户安装CUDA,CUDNN
  10. Python制作简单的终端交互小游戏