feign客户端 修改 服务器列表,SpringCloud(四)--Feign&Turbine

Feign

集成工具(功能整合)远程调用:声明式客户端

ribbon 负载均衡和重试

hystrix 降级和熔断

feign 声明式客户端接口

微服务应用中,ribbon 和 hystrix 总是同时出现,feign 整合了两者,并提供了声明式消费者客户端用 feign 代替 hystrix+ribbon

1460000038360573

只需要声明一个抽象接口,就可以通过接口做远程调用,不需要再使用 RestTemplate 来调用// 调用远程的商品服务,获取订单的商品列表

// 通过注解,配置:

// 1. 调用哪个服务

// 2. 调用服务的哪个路径

// 3. 向路径提交什么参数数据

@FeignClient(name="item-service")

public interface ItemClient {

@GetMapping("/{orderId}")

JsonResult> getItems(@PathVariable String orderId);

}

在这里使用 @GetMapping("/{orderId}"), 指定的是向远程服务调用的路径

新建 sp09-feign 项目

1460000038360566

1460000038360567

pom.xml需要添加 sp01-commons 依赖

application.ymlspring:

application:

name: feign

server:

port: 3001

eureka:

client:

service-url:

defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka

主程序添加 @EnableDiscoveryClient 和 @EnableFeignClientspackage cn.tedu.sp09;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

import org.springframework.cloud.openfeign.EnableFeignClients;

@EnableFeignClients

@EnableDiscoveryClient

@SpringBootApplication

public class Sp09FeignApplication {

public static void main(String[] args) {

SpringApplication.run(Sp09FeignApplication.class, args);

}

}

feign 声明式客户端

feign 利用了熟悉的 spring mvc 注解来对接口方法进行设置,降低了我们的学习成本。

通过这些设置,feign可以拼接后台服务的访问路径和提交的参数

例如:@GetMapping("/{userId}/score")

JsonResult addScore(@PathVariable Integer userId, @RequestParam Integer score);

当这样调用该方法:service.addScore(7, 100);

那么 feign 会向服务器发送请求:http://用户微服务/7/score?score=100注意:如果 score 参数名与变量名不同,需要添加参数名设置:@GetMapping("/{userId}/score")

JsonResult addScore(@PathVariable Integer userId, @RequestParam("score") Integer s

ItemClientpackage cn.tedu.sp09.feign;

import cn.tedu.sp01.pojo.Item;

import cn.tedu.web.util.JsonResult;

import org.springframework.cloud.openfeign.FeignClient;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.PostMapping;

import org.springframework.web.bind.annotation.RequestBody;

import java.util.List;

//根据服务id,从注册表得到主机地址

@FeignClient(name = "item-service")

public interface ItemClient {//封装了RestTemplate

@GetMapping("{orderId}")//(反向)将请求拼接发送

JsonResult> getItems(@PathVariable String orderId);

@PostMapping("/decreaseNumber")//(反向)将请求拼接发送

JsonResult> decreaseNumber(@RequestBody List items);

}

UserClientpackage cn.tedu.sp09.feign;

import cn.tedu.sp01.pojo.User;

import cn.tedu.web.util.JsonResult;

import org.springframework.cloud.openfeign.FeignClient;

import org.springframework.web.bind.annotation.*;

//根据服务id,从注册表得到主机地址

@FeignClient(name = "user-service")

public interface UserClient {//封装了RestTemplate

@GetMapping("{userId}")//(反向)将请求拼接发送

JsonResult getUser(@PathVariable Integer userId);

//....../8/score?score=1000

@GetMapping("/{userId}/score")//(反向)将请求拼接发送

JsonResult> addScore(@PathVariable Integer userId,

@RequestParam Integer score);//@RequestParam 不能省略

}

OrderClientpackage cn.tedu.sp09.feign;

import cn.tedu.sp01.pojo.Order;

import cn.tedu.web.util.JsonResult;

import org.springframework.cloud.openfeign.FeignClient;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.PathVariable;

//根据服务id,从注册表得到主机地址

@FeignClient(name = "order-service")

public interface OrderClient {//封装了RestTemplate

@GetMapping("{orderId}")//(反向)将请求拼接发送

JsonResult getOrder(@PathVariable String orderId);

@GetMapping("/")//(反向)将请求拼接发送

JsonResult> addOrder();

}

FeignControllerpackage cn.tedu.sp09.controller;

import cn.tedu.sp01.pojo.Item;

import cn.tedu.sp01.pojo.Order;

import cn.tedu.sp01.pojo.User;

import cn.tedu.sp09.feign.ItemClient;

import cn.tedu.sp09.feign.OrderClient;

import cn.tedu.sp09.feign.UserClient;

import cn.tedu.web.util.JsonResult;

import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController

@Slf4j

public class FeignController {

@Autowired

private ItemClient itemClient;

@Autowired

private UserClient userClient;

@Autowired

private OrderClient orderClient;

//-----------item-service

@GetMapping("/item-service/{orderId}")

public JsonResult> getItems(@PathVariable String orderId){

return itemClient.getItems(orderId);

}

@PostMapping("/item-service/decreaseNumber")

public JsonResult> decreaseNumber(@RequestBody List items){

return itemClient.decreaseNumber(items);

}

//-----------user-service

@GetMapping("/user-service/{userId}")

public JsonResult getUser(@PathVariable Integer userId){

return userClient.getUser(userId);

}

@GetMapping("/user-service/{userId}/score")

public JsonResult> addScore(@PathVariable Integer userId,Integer score){

return userClient.addScore(userId, score);

}

//-----------order-service

@GetMapping("/order-service/{orderId}")

public JsonResult getOrder(@PathVariable String orderId){

return orderClient.getOrder(orderId);

}

@GetMapping("/order-service")

public JsonResult> addOrder(){

return orderClient.addOrder();

}

}

调用流程

1460000038360571

启动服务,并访问测试

1460000038360565

Feign 集成 Ribbon 负载均衡和重试无需额外配置,feign 默认已启用了 ribbon 负载均衡和重试机制。可以通过配置对参数进行调整

重试的默认配置参数:ConnectTimeout=1000

ReadTimeout=1000

MaxAutoRetries=0

MaxAutoRetriesNextServer=1

application.yml 配置 ribbon 超时和重试ribbon.xxx 全局配置

item-service.ribbon.xxx 对特定服务实例的配置spring:

application:

name: feign

server:

port: 3001

eureka:

client:

service-url:

defaultZone: http://eureka1:2001/eureka,http://eureka2:2002/eureka

# 调整 ribbon 的重试次数

# 针对所有服务的通用配置

ribbon:

MaxAutoRetries: 1

MaxAutoRetriesNextServer: 2

ConnectTimeout: 1000

ReadTimeout: 500

#只针对 item-service这一个服务有效,对其它服务不应用这个配置

item-service:

ribbon:

MaxAutoRetries: 2

启动服务,访问测试

Feign 集成 Hystrix降级和熔断

Feign默认不启用Hystrix,使用feign时不推荐启用Hystrix

启用Hystrix基础配置:hystrix起步依赖

yml中配置启用hystrix

启动类添加注解 @EnableCircuitBreaker

application.yml 添加配置feign:

hystrix:

enabled: true

添加配置,暂时减小降级超时时间,以便后续对降级进行测试......

feign:

hystrix:

enabled: true

hystrix:

command:

default:

execution:

isolation:

thread:

timeoutInMilliseconds: 500

feign + hystrix 降级

feign 远程接口中指定降级类ItemFeignService...

@FeignClient(name="item-service", fallback = ItemFeignServiceFB.class)

public interface ItemFeignService {

...UserFeignService...

@FeignClient(name="user-service", fallback = UserFeignServiceFB.class)

public interface UserFeignService {

...OrderFeignService...

@FeignClient(name="order-service",fallback = OrderFeignServiceFB.class)

public interface OrderFeignService {

...

降级类

降级类需要实现声明式客户端接口,在实现的抽象方法中添加降级代码,

降级类需要添加 @Component 注解ItemFeignServiceFBpackage cn.tedu.sp09.service;

import java.util.List;

import org.springframework.stereotype.Component;

import cn.tedu.sp01.pojo.Item;

import cn.tedu.web.util.JsonResult;

@Component

public class ItemFeignServiceFB implements ItemFeignService {

@Override

public JsonResult> getItems(String orderId) {

return JsonResult.err("无法获取订单商品列表");

}

@Override

public JsonResult decreaseNumber(List items) {

return JsonResult.err("无法修改商品库存");

}

}UserFeignServiceFBpackage cn.tedu.sp09.service;

import org.springframework.stereotype.Component;

import cn.tedu.sp01.pojo.User;

import cn.tedu.web.util.JsonResult;

@Component

public class UserFeignServiceFB implements UserFeignService {

@Override

public JsonResult getUser(Integer userId) {

return JsonResult.err("无法获取用户信息");

}

@Override

public JsonResult addScore(Integer userId, Integer score) {

return JsonResult.err("无法增加用户积分");

}

}OrderFeignServiceFBpackage cn.tedu.sp09.service;

import org.springframework.stereotype.Component;

import cn.tedu.sp01.pojo.Order;

import cn.tedu.web.util.JsonResult;

@Component

public class OrderFeignServiceFB implements OrderFeignService {

@Override

public JsonResult getOrder(String orderId) {

return JsonResult.err("无法获取商品订单");

}

@Override

public JsonResult addOrder() {

return JsonResult.err("无法保存订单");

}

}

启动服务,访问测试

1460000038360569

feign + hystrix 监控和熔断测试

1460000038360568

修改sp09-feign项目pom.xml 添加 hystrix 起步依赖feign 没有包含完整的 hystrix 依赖

右键点击项目,编辑起步依赖,添加hystrix依赖

1460000038322985

org.springframework.cloud

spring-cloud-starter-netflix-hystrix

主程序添加 @EnableCircuitBreakerpackage cn.tedu.sp09;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;

import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

import org.springframework.cloud.openfeign.EnableFeignClients;

@EnableCircuitBreaker

@EnableFeignClients

@EnableDiscoveryClient

@SpringBootApplication

public class Sp09FeignApplication {

public static void main(String[] args) {

SpringApplication.run(Sp09FeignApplication.class, args);

}

}

sp09-feign 配置 actuator,暴露 hystrix.stream 监控端点

actuator 依赖

查看pom.xml, 确认已经添加了 actuator 依赖

org.springframework.boot

spring-boot-starter-actuator

application.yml 暴露 hystrix.stream 端点management:

endpoints:

web:

exposure:

include: hystrix.stream

启动服务,查看监控端点

hystrix dashboard

启动 hystrix dashboard 服务,填入 feign 监控路径,开启监控

访问 http://localhost:4001/hystrix填入 feign 监控路径:

http://localhost:3001/actuator/hystrix.stream

访问微服务,以产生监控数据

1460000038360570

熔断测试用 ab 工具,以并发50次,来发送20000个请求`ab -n 20000 -c 50 http://localhost:3001/item-service/35`断路器状态为 Open,所有请求会被短路,直接降级执行 fallback 方法

1460000038360577

order service 调用商品库存服务和用户服务

1460000038360575

sp09-feign项目关闭,不再使用

1460000038360580

修改 sp04-orderservice 项目,添加 feign,调用 item service 和 user servicepom.xml

application.yml

主程序

ItemFeignService

UserFeignService

ItemFeignServiceFB

UserFeignServiceFB

OrderServiceImpl

pom.xml

1460000038322985右键点击项目编辑起步依赖,添加以下依赖:

actuator

feign

hystrix

application.ymlribbon 重试和 hystrix 超时这里没有设置,采用了默认值spring:

application:

name: order-service

server:

port: 8201

eureka:

client:

service-url:

defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka

feign:

hystrix:

enabled: true

management:

endpoints:

web:

exposure:

include: hystrix.stream

主程序package cn.tedu.sp04;

import org.springframework.boot.SpringApplication;

import org.springframework.cloud.client.SpringCloudApplication;

import org.springframework.cloud.openfeign.EnableFeignClients;

//@EnableDiscoveryClient

//@SpringBootApplication

@EnableFeignClients

@SpringCloudApplication

public class Sp04OrderserviceApplication {

public static void main(String[] args) {

SpringApplication.run(Sp04OrderserviceApplication.class, args);

}

}

ItemFeignServicepackage cn.tedu.sp04.order.feignclient;

import java.util.List;

import org.springframework.cloud.openfeign.FeignClient;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.PostMapping;

import org.springframework.web.bind.annotation.RequestBody;

import cn.tedu.sp01.pojo.Item;

import cn.tedu.web.util.JsonResult;

@FeignClient(name="item-service", fallback = ItemFeignServiceFB.class)

public interface ItemFeignService {

@GetMapping("/{orderId}")

JsonResult> getItems(@PathVariable String orderId);

@PostMapping("/decreaseNumber")

JsonResult decreaseNumber(@RequestBody List items);

}

UserFeignServicepackage cn.tedu.sp04.order.feignclient;

import org.springframework.cloud.openfeign.FeignClient;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.RequestParam;

import cn.tedu.sp01.pojo.User;

import cn.tedu.web.util.JsonResult;

@FeignClient(name="user-service", fallback = UserFeignServiceFB.class)

public interface UserFeignService {

@GetMapping("/{userId}")

JsonResult getUser(@PathVariable Integer userId);

@GetMapping("/{userId}/score")

JsonResult addScore(@PathVariable Integer userId, @RequestParam Integer score);

}

ItemFeignServiceFB获取商品列表的降级方法,模拟使用缓存数据package cn.tedu.sp04.order.feignclient;

import java.util.Arrays;

import java.util.List;

import org.springframework.stereotype.Component;

import cn.tedu.sp01.pojo.Item;

import cn.tedu.web.util.JsonResult;

@Component

public class ItemFeignServiceFB implements ItemFeignService {

@Override

public JsonResult> getItems(String orderId) {

if(Math.random()<0.5) {

return JsonResult.ok().data(

Arrays.asList(new Item[] {

new Item(1,"缓存aaa",2),

new Item(2,"缓存bbb",1),

new Item(3,"缓存ccc",3),

new Item(4,"缓存ddd",1),

new Item(5,"缓存eee",5)

})

);

}

return JsonResult.err("无法获取订单商品列表");

}

@Override

public JsonResult decreaseNumber(List items) {

return JsonResult.err("无法修改商品库存");

}

}

UserFeignServiceFB获取用户信息的降级方法,模拟使用缓存数据package cn.tedu.sp04.order.feignclient;

import org.springframework.stereotype.Component;

import cn.tedu.sp01.pojo.User;

import cn.tedu.web.util.JsonResult;

@Component

public class UserFeignServiceFB implements UserFeignService {

@Override

public JsonResult getUser(Integer userId) {

if(Math.random()<0.4) {

return JsonResult.ok(new User(userId, "缓存name"+userId, "缓存pwd"+userId));

}

return JsonResult.err("无法获取用户信息");

}

@Override

public JsonResult addScore(Integer userId, Integer score) {

return JsonResult.err("无法增加用户积分");

}

}

OrderServiceImplpackage cn.tedu.sp04.order.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import cn.tedu.sp01.pojo.Item;

import cn.tedu.sp01.pojo.Order;

import cn.tedu.sp01.pojo.User;

import cn.tedu.sp01.service.OrderService;

import cn.tedu.sp04.order.feignclient.ItemFeignService;

import cn.tedu.sp04.order.feignclient.UserFeignService;

import cn.tedu.web.util.JsonResult;

import lombok.extern.slf4j.Slf4j;

@Slf4j

@Service

public class OrderServiceImpl implements OrderService {

@Autowired

private ItemFeignService itemService;

@Autowired

private UserFeignService userService;

@Override

public Order getOrder(String orderId) {

//调用user-service获取用户信息

JsonResult user = userService.getUser(7);

//调用item-service获取商品信息

JsonResult> items = itemService.getItems(orderId);

Order order = new Order();

order.setId(orderId);

order.setUser(user.getData());

order.setItems(items.getData());

return order;

}

@Override

public void addOrder(Order order) {

//调用item-service减少商品库存

itemService.decreaseNumber(order.getItems());

//TODO: 调用user-service增加用户积分

userService.addScore(7, 100);

log.info("保存订单:"+order);

}

}

order-service 配置启动参数,启动两台服务器--server.port=8201

--server.port=8202

1460000038360582

1460000038360581

1460000038360574

1460000038360578

1460000038360576

启动服务,访问测试

1460000038360579

hystrix dashboard 监控 order service 断路器

1460000038360587

hystrix dashboard 监控 order service 断路器

1460000038360587

Turbine

hystrix + turbine 集群聚合监控

1460000038360584

hystrix dashboard 一次只能监控一个服务实例,使用 turbine 可以汇集监控信息,将聚合后的信息提供给 hystrix dashboard 来集中展示和监控

新建 sp10-turbine 项目

1460000038360585

1460000038360588

pom.xml<?xml version="1.0" encoding="UTF-8"?>

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

4.0.0

org.springframework.boot

spring-boot-starter-parent

2.2.1.RELEASE

cn.tedu

sp10-turbine

0.0.1-SNAPSHOT

sp10-turbine

Demo project for Spring Boot

1.8

Hoxton.RELEASE

org.springframework.cloud

spring-cloud-starter-netflix-eureka-client

org.springframework.cloud

spring-cloud-starter-netflix-turbine

org.springframework.boot

spring-boot-starter-test

test

org.junit.vintage

junit-vintage-engine

org.springframework.cloud

spring-cloud-dependencies

${spring-cloud.version}

pom

import

org.springframework.boot

spring-boot-maven-plugin

application.ymlspring:

application:

name: turbin

server:

port: 5001

eureka:

client:

service-url:

defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka

turbine:

app-config: order-service

cluster-name-expression: new String("default")

主程序

添加 @EnableTurbine 和 @EnableDiscoveryClient 注解package cn.tedu.sp10;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

import org.springframework.cloud.netflix.turbine.EnableTurbine;

@EnableTurbine

@EnableDiscoveryClient

@SpringBootApplication

public class Sp10TurbineApplication {

public static void main(String[] args) {

SpringApplication.run(Sp10TurbineApplication.class, args);

}

}

访问测试

1460000038360583

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值