只需要定义一个抽象的接口,就可以通过接口调用远程服务,不需要写具体调用代码.
例如调用后台商品服务,接口可以这样定义
@FeignClient(name="item-service")
public interface ItemFeignClient {
@GetMapping("/{orderId}")
JsonResult<List<Item>> getItems(@PathVarible String orderId);
}
spring:
application:
name: feign
server:
port: 3001
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
@EnableDiscoveryClient
(开启eureka)和 @EnableFeignClients
(开启 feign)
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class Sp09FeignApplication {
public static void main(String[] args) {
SpringApplication.run(Sp09FeignApplication.class, args);
}
}
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
@GetMapping("/{userId}/score")
JsonResult addScore(@PathVariable Integer userId, @RequestParam("score") Integer s);
@FeignClient("item-service")
public interface ItemFeignService {
@GetMapping("/{orderId}")
JsonResult<List<Item>> getItems(@PathVariable String orderId);
@PostMapping("/decreaseNumber")
JsonResult decreaseNumber(@RequestBody List<Item> items);
}
@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);
}
}
重试的默认配置参数:
ConnectTimeout=1000
ReadTimeout=1000
MaxAutoRetries=0
MaxAutoRetriesNextServer=1
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
#局部配置
item-service:
ribbon:
MaxAutoRetries: 1
MaxAutoRetriesNextServer: 2
ConnectTimeout: 1000
ReadTimeout: 500
feign默认没有启用hystrix,添加配置,启用hystrix
feign.hystrix.enabled=true
feign:
hystrix:
enabled: true
启用hystrix,访问服务
默认1秒会快速失败,没有降级方法时,会显示空白页
ribbon超时时间至少应小于ystrix的超时时间
......
feign:
hystrix:
enabled: true
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 500
远程调用事变,会执行降级类中的代码
添加一个单独的降级类,需要实现声明式客户端接口
@Component
public class ItemFeignClientFB implements ItemFeignClient {
实现降级方法,返回降级响应
}
在接口上,还需要指定降级类
@FeignClient(name="item-service",fallback=降级类)
interface ItemFeignClient {
}
...
@FeignClient(name="item-service", fallback = ItemFeignServiceFB.class)
public interface ItemFeignService {
...
降级类需要实现远程接口
@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("无法修改商品库存");
}
}
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
@EnableCircuitBreaker
@EnableCircuitBreaker
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class Sp09FeignApplication {
public static void main(String[] args) {
SpringApplication.run(Sp09FeignApplication.class, args);
}
}
查看pom.xml,确认已经添加了 actuator
依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
management:
endpoints:
web:
exposure:
include: hystrix.stream
http://localhost:端口/actuator
启动 hystrix dashboard 服务,填入 feign 监控路径,开启监控
访问 http://localhost:4001/hystrix