SpringCloud+Eureka+Feign+Ribbon的简化搭建流程,加入熔断,网关和Redis缓存[2]
程序员文章站
2022-06-05 17:42:24
SpringCloud+Eureka+Feign+Ribbon的简化搭建流程,加入熔断,网关和Redis缓存 ......
作者:故事我忘了¢
个人微信公众号:程序猿的月光宝盒
个人微信公众号:程序猿的月光宝盒
前提:本篇是基于
springcloud+eureka+feign+ribbon的简化搭建流程和crud练习[1]
的修改与拓展
1.修改consumer
的centerfeign.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.修改consumer
的centercontroller.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/**/
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数据
以上....