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

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

前提:本篇是基于

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/html

发现全部服务已经注册java

图片

正常走provider没有问题mysql

图片


1577497250598

图片

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

图片

那怎么走容错?spring

如今手动中止一个providersql

图片

由于这里我开了负载均衡策略(在consumer中的配置文件中provider.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule),因此有必定概率触发熔断器,数据库

1577497881423

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

图片

1577498055072

这里我测了这么屡次,都没有走熔断,因此显然不走,为什么?缓存

由于没有手动设置负载均衡策略的话,默认走的是轮询.机制,啥是Ribbon轮询机制?服务器

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

以上,我的理解,如有误请指正,よろしくお願いします~


如今,既然一台服务器工做是没有问题 那我两台provider所有中止呢?

图片

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

1577498433508

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

1577510704686

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数据

图片

1577637422115

以上....

相关文章
相关标签/搜索