feign是ribbon +hystrix 的整合
01.新建 sp09-feign 項目
第一步:
第二步:選擇依賴:
pom.xml
需要添加 sp01-commons 依賴:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>cn.tedu</groupId>
<artifactId>sp09-feign</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>sp09-feign</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR12</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>cn.tedu</groupId>
<artifactId>sp01-commons</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
第三步:修改sp09-feign項目的application.yml
spring:
application:
name: feign
server:
port: 3001
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
第四步:sp09-feign的主程序添加 @EnableDiscoveryClient 和 @EnableFeignClients
package 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;
@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication
public class Sp09FeignApplication {
public static void main(String[] args) {
SpringApplication.run(Sp09FeignApplication.class, args);
}
}
02.feign 聲明式客戶端
feign 利用了我們熟悉的 spring mvc 注解來對接口方法進行設置,降低了我們的學習成本。
通過這些設置,feign可以拼接后臺服務的訪問路徑和提交的參數(shù)
例如:
@GetMapping("/{userId}/score")
JsonResult addScore(@PathVariable Integer userId, @RequestParam Integer score);
當這樣調(diào)用該方法:
service.addScore(7, 100);
那么 feign 會向服務器發(fā)送請求:
http://用戶微服務/7/score?score=100
注意:如果 score 參數(shù)名與變量名不同,需要添加參數(shù)名設置:
@GetMapping("/{userId}/score")
JsonResult addScore(@PathVariable Integer userId, @RequestParam("score") Integer s);
第一步:聲明三個代理接口
這里的三個Feign類型service接口,就好像是ribbon中的ribbonController(但是沒有注解controller,并不能接受客戶端的request請求,所以只是類似),只是調(diào)用service中的方法。具體方法的實現(xiàn)還是要在原來的service中去完成。
@FeignClient(“item-service”),中的item-service是在service服務中的application.yml文件中的spring.application.name來確定的
ItemFeignService:
package cn.tedu.sp09.service;
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("item-service")
public interface ItemFeignService {
@GetMapping("/{orderId}")
JsonResult<List<Item>> getItems(@PathVariable String orderId);
@PostMapping("/decreaseNumber")
JsonResult decreaseNumber(@RequestBody List<Item> items);
}
UserFeignService
注意,如果請求參數(shù)名與方法參數(shù)名不同,@RequestParam不能省略,并且要指定請求參數(shù)名:
@RequestParam(“score”) Integer s
package cn.tedu.sp09.service;
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("user-service")
public interface UserFeignService {
@GetMapping("/{userId}")
JsonResult<User> getUser(@PathVariable Integer userId);
// 拼接路徑 /{userId}/score?score=新增積分
@GetMapping("/{userId}/score")
JsonResult addScore(@PathVariable Integer userId, @RequestParam Integer score);
}
OrderFeignService:
package cn.tedu.sp09.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import cn.tedu.sp01.pojo.Order;
import cn.tedu.web.util.JsonResult;
@FeignClient("order-service")
public interface OrderFeignService {
@GetMapping("/{orderId}")
JsonResult<Order> getOrder(@PathVariable String orderId);
@GetMapping("/")
JsonResult addOrder();
}
第二步:編寫FeignController,這個是用來接受web請求的,是真正的controller
FeignController:
package cn.tedu.sp09.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
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 org.springframework.web.bind.annotation.RestController;
import cn.tedu.sp01.pojo.Item;
import cn.tedu.sp01.pojo.Order;
import cn.tedu.sp01.pojo.User;
import cn.tedu.sp09.service.ItemFeignService;
import cn.tedu.sp09.service.OrderFeignService;
import cn.tedu.sp09.service.UserFeignService;
import cn.tedu.web.util.JsonResult;
@RestController
public class FeignController {
@Autowired
private ItemFeignService itemService;
@Autowired
private UserFeignService userService;
@Autowired
private OrderFeignService orderService;
@GetMapping("/item-service/{orderId}")
public JsonResult<List<Item>> getItems(@PathVariable String orderId) {
return itemService.getItems(orderId);
}
@PostMapping("/item-service/decreaseNumber")
public JsonResult decreaseNumber(@RequestBody List<Item> items) {
return itemService.decreaseNumber(items);
}
@GetMapping("/user-service/{userId}")
public JsonResult<User> getUser(@PathVariable Integer userId) {
return userService.getUser(userId);
}
@GetMapping("/user-service/{userId}/score")
public JsonResult addScore(@PathVariable Integer userId, Integer score) {
return userService.addScore(userId, score);
}
@GetMapping("/order-service/{orderId}")
public JsonResult<Order> getOrder(@PathVariable String orderId) {
return orderService.getOrder(orderId);
}
@GetMapping("/order-service")
public JsonResult addOrder() {
return orderService.addOrder();
}
}
為什么可以直接在@GetMapping(“/order-service”)中直接寫order-service,因為feign有ribbon技術,可以直接調(diào)用服務的服務名
調(diào)用流程
第三步:啟動服務,并訪問測試
http://eureka1:2001
http://localhost:3001/item-service/35
http://localhost:3001/item-service/decreaseNumber
使用postman,POST發(fā)送以下格式數(shù)據(jù):
[{“id”:1, “name”:“abc”, “number”:23},{“id”:2, “name”:“def”, “number”:11}]
http://localhost:3001/user-service/7
http://localhost:3001/user-service/7/score?score=100
http://localhost:3001/order-service/123abc
http://localhost:3001/order-service/
03.配合ribbon 負載均衡和重試
無需額外配置,feign 默認已啟用了 ribbon 負載均衡和重試機制??梢酝ㄟ^配置對參數(shù)進行調(diào)整
重試的默認配置參數(shù):
ConnectTimeout=1000
ReadTimeout=1000
MaxAutoRetries=0
MaxAutoRetriesNextServer=1
第一步:可以在sp09-feign 項目的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:
ConnectTimeout: 1000
ReadTimeOut: 1000
MaxAutoRetries: 1
MaxAutoRetriesNextServer: 2
item-service:
ribbon:
ConnectTimeout: 1000
ReadTimeOut: 1000
MaxAutoRetries: 2
MaxAutoRetriesNextServer: 1
啟動服務,訪問測試
http://localhost:3001/item-service/35
04.feign + hystrix 降級
feign 啟用 hystrix
第一步:feign 默認沒有啟用 hystrix,添加配置,啟用 hystrix
feign.hystrix.enabled=true
application.yml 添加配置
feign:
hystrix:
enabled: true
第二步:降級類
降級類需要實現(xiàn)遠程接口
ItemFeignServiceFB
package 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<List<Item>> getItems(String orderId) {
return JsonResult.err("獲取訂單失敗");
}
@Override
public JsonResult decreaseNumber(List<Item> items) {
return JsonResult.err("減少庫存失敗");
}
}
UserFeginServiceFB
package 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<User> getUser(Integer userId) {
return JsonResult.err("獲取用戶失敗");
}
@Override
public JsonResult addScore(Integer userId, Integer score) {
return JsonResult.err("增加積分失敗");
}
}
OrderFeignServiceFB
package 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<Order> getOrder(String orderId) {
return JsonResult.err("獲取訂單失敗");
}
@Override
public JsonResult addOrder() {
return JsonResult.err("保存訂單失敗");
}
}
第三步:在代理接口(ItemFeignService)中去聲明降級類
遠程調(diào)用失敗, 會執(zhí)行降級類中的代碼,在注解@FeignClient中去添加屬性fallback
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 {
04.feign + hystrix 監(jiān)控和熔斷測試第一步:修改sp09-feign項目
pom.xml 添加 hystrix 起步依賴,feign 沒有包含完整的 hystrix 依賴
右鍵點擊項目,編輯起步依賴,添加hystrix依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
第二步:主程序添加 @EnableCircuitBreaker
package cn.tedu.sp09;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
//@EnableCircuitBreaker
//@EnableDiscoveryClient
//@SpringBootApplication
@SpringCloudApplication
@EnableFeignClients
public class Sp09FeignApplication {
public static void main(String[] args) {
SpringApplication.run(Sp09FeignApplication.class, args);
}
}
第三步:sp09-feign 配置 actuator,暴露 hystrix.stream 監(jiān)控端點
actuator 依賴
查看pom.xml, 確認已經(jīng)添加了 actuator 依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
application.yml 暴露 hystrix.stream 端點
management:
endpoints:
web:
exposure:
include: hystrix.stream
第四步:啟動服務,查看監(jiān)控端點
http://localhost:3001/actuator
第五步:啟動hystrix dashboard
啟動 hystrix dashboard 服務,填入feign監(jiān)控路徑,開啟監(jiān)控
訪問 http://localhost:4001/hystrix
在其中填入 feign 監(jiān)控路徑:
http://localhost:3001/actuator/hystrix.stream
訪問微服務,以產(chǎn)生監(jiān)控數(shù)據(jù)
http://localhost:3001/item-service/35
http://localhost:3001/user-service/7
http://localhost:3001/user-service/7/score?score=100
http://localhost:3001/order-service/123abc
http://localhost:3001/order-service/
第六步:熔斷測試
用ab工具,以并發(fā)50次,來發(fā)送20000個請求文章來源:http://www.zghlxwxcb.cn/news/detail-497056.html
ab -n 20000 -c 50 http://localhost:3001/item-service/35
斷路器狀態(tài)為 Open,所有請求會被短路,直接降級執(zhí)行fallback方法文章來源地址http://www.zghlxwxcb.cn/news/detail-497056.html
到了這里,關于微服務springcloud 06.feign框架,配合ribbon 負載均衡和重試,配合hystrix 降級,監(jiān)控和熔斷測試的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!