作者:故事我忘了
个人微信公众号:程序猿的月光宝盒

[toc]
## 前提:本篇是基于

SpringCloud+Eureka+Feign+Ribbon的简化搭建流程和CRUD练习[1]

的修改与拓展


1.修改consumerCenterFeign.java,把返回值全部设置为String

/**
* 是consumer调用provider(需要指定provider的名字)
* 请求的清单列表:规定调用地址、参数、返回值
* 在正常走通的时候不走CenterFeignFallBack,当provider down的时候走熔断器,相当于是类的try-catch
*/
@FeignClient(name = "provider",fallback = CenterFeignFallBack.class)
public interface CenterFeign {
@GetMapping("/optionData.do")
public String optionData(); @PostMapping("/showEmpData.do")
//Feign:不支持对象传参,所以要用@RequestBody
public String showEmpData(@RequestBody Emp emp); @PostMapping("/add.do")
public String add(@RequestBody Emp emp); @PostMapping("/edit.do")
public String edit(@RequestBody Emp emp); @GetMapping("/del.do")
public String del(@RequestParam("empno") Integer empno);
}

2.在CenterFeign.java的同包下创建实现了CenterFeign接口的CenterFeignFallBack.java作为熔断器

@Component
public class CenterFeignFallBack implements CenterFeign {
@Override
public String optionData() {
return "provider-optionData-error";
} @Override
public String showEmpData(Emp emp) {
return "provider-showEmpData-error";
} @Override
public String add(Emp emp) {
return "provider-add-error";
} @Override
public String edit(Emp emp) {
return "provider-edit-error";
} @Override
public String del(Integer empno) {
return "provider-del-error";
}
}

3.修改consumerCenterController.java,返回值全改为String

@RestController
public class CenterController{
@Resource
private CenterFeign centerFeign; @GetMapping("/optionData-consumer.do")
public String optionData() {
return centerFeign.optionData();
} @PostMapping("/showEmpData-consumer.do")
public String showEmpData(@RequestBody Emp emp) {
return centerFeign.showEmpData(emp);
} @PostMapping("/add-consumer.do")
public String add(@RequestBody Emp emp) {
return centerFeign.add(emp);
} @PostMapping("/edit-consumer.do")
public String edit(@RequestBody Emp emp) {
return centerFeign.edit(emp);
} @GetMapping("/del-consumer.do")
public String del(@RequestParam("empno") Integer empno) {
return centerFeign.del(empno);
}
}

4.确认consumer中的配置文件application.properties中有没有开启熔断feign.hystrix.enabled=true,没有的话加上

#端口号
server.port=8764
#应用名
spring.application.name=consumer
#eureka客户端服务url默认区域
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
#开启熔断器
feign.hystrix.enabled=true
#下线名称.ribbon.NF加载平衡规则类名,这里先注释
provider.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule

5.开启服务测试

访问http://localhost:8761/

发现所有服务已经注册

正常走provider没有问题


走consumer也没有问题,只是返回的格式是字符串类型,不是json类型,但是没关系,格式还是json的格式,前台该怎么转还能怎么转,不影响

那怎么走容错?

现在手动停止一个provider

因为这里我开了负载均衡策略(在consumer中的配置文件中provider.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule),所以有一定几率触发熔断器,

这就相当于类之间的try-catch,没有熔断器的话这里百分百是报错误代码.那这里我先把负载均衡关掉,在测试有没有走容错,(猜一下,会走吗?)

这里我测了这么多次,都没有走熔断,所以显然不走,为何?

因为没有手动设置负载均衡策略的话,默认走的是轮询.机制,啥是Ribbon轮询机制?

简单的说就是有abc三台服务器,正常的情况下走a->b->c,在有一台down了的时候,那台就自动跳过,比如b down了,那么就是a->c

以上,个人理解,若有误请指正,よろしくお願いします~


现在,既然一台服务器工作是没有问题 那我两台provider全部停止呢?

那答案是肯定的,绝壁走容错~~

6.测试完没有问题,现在添加网关功能模块

新建模块(Spring initializr)zuul-client

7.编辑配置文件application.properties

#网关端口
server.port=8765
#应用名
spring.application.name=zuul
#网关路径提供者,后面的**表示:xxx.do
zuul.routes.provider=/pro/**/
#网关路径消费者,后面的**表示:xxx.do
zuul.routes.consumer=/con/**/
#网关走熔断机制
#ribbon超时设置
ribbon.ReadTimeout=30000
ribbon.ConnectTimeout=30000

8.在启动类上添加注解

//开启网关代理
@EnableZuulProxy
//开启eureka客户端
@EnableEurekaClient
@SpringBootApplication
public class ZuulClientApplication { public static void main(String[] args) {
SpringApplication.run(ZuulClientApplication.class, args);
} }

9.开启服务测试


测试provider

测试consumer

10.网关作用

统一了所有客户端的ip地址和端口号,我们只要给不同层级的应用起别名就ok了(就是这里的)

11.加入Redis缓存

11.1在provider-one模块的pom文件中加入redis依赖

 <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

11.2修改provider-one模块的DeptServiceImpl文件,加入 @Autowired private RedisTemplate redisTemplate;

@Service
public class DeptServiceImpl implements DeptService {
@Autowired
private DeptMapper deptMapper;
@Autowired
private RedisTemplate redisTemplate; @Override
public Map<String, Object> optionData() {
Map<String, Object> map=new HashMap<>();
List<Map<String, Object>> list = deptMapper.selAllDeptData();
// 定义Redis存储集合的对象
ListOperations<String,Map<String,Object>> redisList = redisTemplate.opsForList();
//拼接Redis中存储数据对应的key
String key = "depts";
//判断Redis中是否有key,没有就说明是第一次访问,将数据放入Redis
if(!redisTemplate.hasKey(key)){
//直接将数据库查询出来的值放入Redis
System.out.println("provider-one-optionData的值已经放入Redis");
redisList.leftPushAll(key,list);
}
map.put("data",list);
return map;
}
}

11.3对应的 修改DeptService,返回值变成map

public interface DeptService {
Map<String,Object> optionData();
}

11.4修改CenterController,把返回值类型改为Map

    public Map<String, Object> optionData() {
return deptService.optionData();
}

11.5同样的在provider-two的pom.xml中加入redis依赖

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

11.6修改provider-two模块的DeptServiceImpl文件,加入 @Autowired private RedisTemplate redisTemplate;

@Service
public class DeptServiceImpl implements DeptService {
@Autowired
private DeptMapper deptMapper;
@Autowired
private RedisTemplate redisTemplate; @Override
public Map<String, Object> optionData() {
Map<String, Object> map=new HashMap<>();
List<Map<String, Object>> list = deptMapper.selAllDeptData();
// 定义Redis存储集合的对象
ListOperations<String,Map<String,Object>> redisList = redisTemplate.opsForList();
//拼接Redis中存储数据对应的key
String key = "depts";
//判断Redis中是否有key,没有就说明是第一次访问,将数据放入Redis
if(!redisTemplate.hasKey(key)){
//直接将数据库查询出来的值放入Redis
System.out.println("provider-two-optionData的值已经放入Redis");
redisList.leftPushAll(key,list);
}
map.put("data",list);
return map;
}
}

11.7对应的 修改DeptService,返回值变成map

public interface DeptService {
Map<String,Object> optionData();
}

11.8修改CenterController,把返回值类型改为Map

    public Map<String, Object> optionData() {
return deptService.optionData();
}

11.9更新provider-one模块的配置文件application.properties,加入Redis配置

#服务端口号
server.port=8762
#应用名
spring.application.name=provider
#eureka客户端服务url默认区域
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/ #数据源驱动类名
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#数据源url
spring.datasource.url=jdbc:mysql:///kh75
#数据源用户名
spring.datasource.username=root
#数据源密码
spring.datasource.password=admin #后期会写mapper.xml,这里先注释
#mybatis.mapper-locations=classpath:mapper/*.xml #给实体类起别名,同样这里先注释
#mybatis.type-aliases-package=cn.kgc.vo #配置Redis
spring.redis.port=6379
#redis所在的主机地址
spring.redis.host=xxx.xxx.xxx
spring.redis.database=0

11.10更新provider-two模块的配置文件application.properties,加入Redis配置

#服务端口号
server.port=8763
#应用名
spring.application.name=provider
#eureka客户端服务url默认区域
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/ #数据源驱动类名
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#数据源url
spring.datasource.url=jdbc:mysql:///kh75
#数据源用户名
spring.datasource.username=root
#数据源密码
spring.datasource.password=admin #后期会写mapper.xml,这里先注释
#mybatis.mapper-locations=classpath:mapper/*.xml #给实体类起别名,同样这里先注释
#mybatis.type-aliases-package=cn.kgc.vo
#配置Redis
spring.redis.port=6379
#redis所在的主机地址
spring.redis.host=xxx.xxx.xx
spring.redis.database=0

11.11更新consumer的CenterFeign,所有返回值都是map

@FeignClient(name = "provider",fallback = CenterFeignFallBack.class)
public interface CenterFeign {
@GetMapping("/optionData.do")
Map<String,Object> optionData(); @PostMapping("/showEmpData.do")
//Feign:不支持对象传参,所以要用@RequestBody
Map<String,Object> showEmpData(@RequestBody Emp emp); @PostMapping("/add.do")
Map<String,Object> add(@RequestBody Emp emp); @PostMapping("/edit.do")
Map<String,Object> edit(@RequestBody Emp emp); @GetMapping("/del.do")
Map<String,Object> del(@RequestParam("empno") Integer empno);
}

11.12更新CenterFeignFallBack

@Component
public class CenterFeignFallBack implements CenterFeign {
private Map<String, Object> map = new HashMap<> ();
@Autowired
private RedisTemplate redisTemplate;
@Override
public Map<String,Object> optionData() {
ListOperations<String,Map<String,Object>> redisList = redisTemplate.opsForList();
map.put("msg","provider-optionData-error");
map.put("feign-data",redisList.range("depts",0,-1));
return map;
} @Override
public Map<String,Object> showEmpData(Emp emp) {
ListOperations<String,Map<String,Object>> redisList = redisTemplate.opsForList();
map.put("msg","provider-showEmpData-error");
//这里对应的serviceImp里面还没修改成Redis,先放着
map.put("feign-data",redisList.range("emps",0,-1));
return map;
} @Override
public Map<String,Object> add(Emp emp) {
map.put("msg","provider-add-error");
return map;
} @Override
public Map<String,Object> edit(Emp emp) {
map.put("msg","provider-edit-error");
return map;
} @Override
public Map<String,Object> del(Integer empno) {
map.put("msg","provider-del-error");
return map;
}
}

11.13再修改consumer中的CenterController,返回值也全改成Map

@RestController
public class CenterController{
@Resource
private CenterFeign centerFeign; @GetMapping("/optionData-consumer.do")
public Map<String,Object> optionData() {
return centerFeign.optionData();
} @PostMapping("/showEmpData-consumer.do")
public Map<String,Object> showEmpData(@RequestBody Emp emp) {
return centerFeign.showEmpData(emp);
} @PostMapping("/add-consumer.do")
public Map<String,Object> add(@RequestBody Emp emp) {
return centerFeign.add(emp);
} @PostMapping("/edit-consumer.do")
public Map<String,Object> edit(@RequestBody Emp emp) {
return centerFeign.edit(emp);
} @GetMapping("/del-consumer.do")
public Map<String,Object> del(@RequestParam("empno") Integer empno) {
return centerFeign.del(empno);
}
}

11.14检查consumer的pom文件里是否有加入Redis依赖,没有加上...

11.15 打开所有模块进行测试

把提供者断掉,理论上走熔断和redis数据

以上....

SpringCloud+Eureka+Feign+Ribbon的简化搭建流程,加入熔断,网关和Redis缓存[2]的更多相关文章

  1. SpringCloud+Eureka+Feign+Ribbon的简化搭建流程和CRUD练习

    作者:个人微信公众号:程序猿的月光宝盒 环境:win10--idea2019--jdk8 1.搭建Eureka服务模块 1.1 新建eureka服务模块(Sping Initializr) 取名为eu ...

  2. SpringCloud+Eureka+Feign+Ribbon+zuul的简化搭建流程和CRUD练习

    环境:win10--idea2019--jdk8 1.搭建Eureka服务模块 1.1 新建eureka服务模块(Sping Initializr) 取名为eureka-server,并添加如下Dep ...

  3. springCloud——Eureka、Ribbon理解

    一. 服务注册中心.服务提供者.服务消费者 如何通信? 客户端: 应用主类中配置@EnableDiscoveryClient application.properties中配置defaultZone指 ...

  4. springcloud微服务实战:Eureka+Zuul+Feign/Ribbon+Hystrix Turbine+SpringConfig+sleuth+zipkin

    相信现在已经有很多小伙伴已经或者准备使用springcloud微服务了,接下来为大家搭建一个微服务框架,后期可以自己进行扩展.会提供一个小案例: 服务提供者和服务消费者 ,消费者会调用提供者的服务,新 ...

  5. SpringCloud基础概念学习笔记(Eureka、Ribbon、Feign、Zuul)

    SpringCloud基础概念学习笔记(Eureka.Ribbon.Feign.Zuul) SpringCloud入门 参考: https://springcloud.cc/spring-cloud- ...

  6. SpringCloud学习笔记(六):Feign+Ribbon负载均衡

    简介 官网解释: http://projects.spring.io/spring-cloud/spring-cloud.html#spring-cloud-feign Feign是一个声明式WebS ...

  7. springcloud微服务实战:Eureka+Zuul+Ribbon+Hystrix+SpringConfig

    原文地址:http://blog.csdn.net/yp090416/article/details/78017552 springcloud微服务实战:Eureka+Zuul+Ribbon+Hyst ...

  8. springCloud系列教程01:Eureka 注册中心集群搭建

    springCloud系列教程包含如下内容: springCloud系列教程01:Eureka 注册中心集群搭建 springCloud系列教程02:ConfigServer 配置中心server搭建 ...

  9. SpringCloud系列五:Ribbon 负载均衡(Ribbon 基本使用、Ribbon 负载均衡、自定义 Ribbon 配置、禁用 Eureka 实现 Ribbon 调用)

    1.概念:Ribbon 负载均衡 2.具体内容 现在所有的服务已经通过了 Eureka 进行了注册,那么使用 Eureka 注册的目的是希望所有的服务都统一归属到 Eureka 之中进 行处理,但是现 ...

随机推荐

  1. 7、Maven插件

    什么是maven插件? maven 实际上是一类依赖插件执行的框架,每个任务实际上是由插件完成,Maven插件通常被用来 创建jar文件 创建war文件 编译代码文件 代码单元测试 创建工程文档 创建 ...

  2. 《深入理解Java虚拟机》读书笔记四

    第五章 调优案例分析与实战

  3. 吴裕雄 python 机器学习——模型选择学习曲线learning_curve模型

    import numpy as np import matplotlib.pyplot as plt from sklearn.svm import LinearSVC from sklearn.da ...

  4. vue动态生成组件

    单个组件引用,引入此文件js.全局使用,注册到vue的main文件Vue.prototype.create = Create create.js import Vue from 'vue';impor ...

  5. 异常的jvm(java虚拟机)与异常处理try catch与throwable

  6. 【译】高级T-SQL进阶系列 (四)【上篇】:使用游标进行行级别处理

    [译注:此文为翻译,由于本人水平所限,疏漏在所难免,欢迎探讨指正] 原文链接:传送门. 正常来说,使用游标并不是处理记录集的最佳方式.然而当一个经验丰富的程序员第一次开始写TSQL时,他们经常会寻找其 ...

  7. Spring Bean 有关的那些注解

    尊重原著直接贴链接 https://mp.weixin.qq.com/s/7lhpEo73KG3-xPgbFiaLHw

  8. 使用 yum 安装 MariaDB 与 MariaDB 的简单配置

    1.安装MariaDB 安装命令 yum -y install mariadb mariadb-server 安装完成MariaDB,首先启动MariaDB,两条命令都可以 systemctl sta ...

  9. 第六节:前后端交互之axios用法及async异步编程

    一. axios用法 参考: API文档: https://www.kancloud.cn/yunye/axios/234845 GitHub: https://github.com/axios/ax ...

  10. abp方法权限

    一.自定义一个权限实体,也可以直接用abp的PermissionNames类 二.重写PermissionChecker中的IsGrantedAsync方法 public override async ...