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

以上....

相關文章
相關標籤/搜索