介绍

Feign是从Netflix中分离出来的轻量级项目,能够在类接口上添加注释,成为一个REST API 客户端。

Feign中对 Hystrix 有依赖关系。Feign只是一个便利的rest框架,简化调用,最后还是通过ribbon在注册服务器中找到服务实例,然后对请求进行分配。

实际项目

在入口程序中添加注释

@EnableFeignClients

REST API 客户端

@FeignClient(value = "ticket-service", configuration = YeaFeignConfiguration.class,fallback = TicketClientHystrix.class)

interface TicketClient {

@RequestMapping(method = RequestMethod.POST, value = "/create")

Message create(

@RequestParam(value = "Type") Integer Type,

@RequestParam(value = "amount") String amount,

@RequestParam(value = "userId") String userId,

@RequestParam(value = "mobile") String mobile,

@RequestParam(value = "status") Integer status,

@RequestParam(value = "belong") Integer belong,

@RequestParam(value = "useProfit")String useProfit,

@RequestParam(value = "useCounter")String useCounter);

}

自定义FeignConfiguration属性

@Configuration

public class YeaFeignConfiguration {

public static final int CONNECT_TIMEOUT_MILLIS = 5000;

public static final int READ_TIMEOUT_MILLIS = 5000;

@Bean

public Logger.Level feignLogger() {

return Logger.Level.FULL;

}

@Bean

public Request.Options options() {

return new Request.Options(CONNECT_TIMEOUT_MILLIS, READ_TIMEOUT_MILLIS);

}

}

pom.xml

io.github.openfeign

feign-core

${project.version}

io.github.openfeign

feign-gson

${project.version}

Feign 原生示例

获取URL的代码,然后封装成对象返回

public class GitHubExample {

interface GitHub {

class Repository {

String name;

}

class Contributor {

String login;

}

@RequestLine("GET /users/{username}/repos?sort=full_name")

List repos(@Param("username") String owner);

@RequestLine("GET /repos/{owner}/{repo}/contributors")

List contributors(@Param("owner") String owner, @Param("repo") String repo);

/** Lists all contributors for all repos owned by a user. */

default List contributors(String owner) {

return repos(owner).stream().flatMap(repo -> contributors(owner, repo.name).stream()).map(c -> c.login)

.distinct().collect(Collectors.toList());

}

static GitHub connect() {

Decoder decoder = new GsonDecoder();

return Feign.builder().decoder(decoder).errorDecoder(new GitHubErrorDecoder(decoder))

.logger(new Logger.ErrorLogger()).logLevel(Logger.Level.BASIC)

.target(GitHub.class, "https://api.github.com");

}

}

static class GitHubClientError extends RuntimeException {

private String message; // parsed from json

@Override

public String getMessage() {

return message;

}

}

static class GitHubErrorDecoder implements ErrorDecoder {

final Decoder decoder;

final ErrorDecoder defaultDecoder = new ErrorDecoder.Default();

GitHubErrorDecoder(Decoder decoder) {

this.decoder = decoder;

}

@Override

public Exception decode(String methodKey, Response response) {

try {

return (Exception) decoder.decode(response, GitHubClientError.class);

} catch (IOException fallbackToDefault) {

return defaultDecoder.decode(methodKey, response);

}

}

}

public static void main(String... args) {

GitHub github = GitHub.connect();

System.out.println("Let's fetch and print a list of the contributors to this org.");

List contributors = github.contributors("netflix");

for (String contributor : contributors) {

System.out.println(contributor);

}

System.out.println("Now, let's cause an error.");

try {

github.contributors("netflix", "some-unknown-project");

} catch (GitHubClientError e) {

System.out.println(e.getMessage());

}

}

}

Feign其他特性

FEIGN CLIENT WITH HYSTRIXOBSERVABLE WRAPPER

With Hystrix on the classpath, you can also return a HystrixComman

基础用法

@FeignClient("http://notification-service")

public interface NotificationVersionResource {

@RequestMapping(value = "/version", method = GET)

String version();

}

细粒度操作

@FeignClient("http://notification-service")

public interface NotificationVersionResource {

@RequestMapping(value = "/version", method = GET)

HystrixObservable version();

}

FEIGN CLIENT WITH HYSTRIX FALLBACK

Feign Clients能直接使用降级功能,最简单的方式就是使用接口,在接口中实现你的降级代码,在服务端发生错误的时候将会被调用。

@FeignClient("http://notification-service")

public interface NotificationResource {

@RequestMapping(value = "/notifications", method = GET)

List findAll();

}

public class NotificationResourceImpl implements NotificationResource {

@Override

public List findAll() {

return new ArrayList<>();

}

}

使用外部链接

之前的示例都是在服务发现中,使用service的Name 去访问,但是同样的也支持使用外部链接去访问。

@FeignClient(name = "reddit-service", url = "${com.deswaef.reddit.url}")

public interface RedditResource {

@RequestMapping(method = RequestMethod.GET, value = "/java.json")

RedditResponse posts();

}

可选配置项

Spring Cloud Netflix 为 Feign提供了下面默认的配置Bean

Decoder feignDecoder: ResponseEntityDecoder

Encoder feignEncoder: SpringEncoder

Logger feignLogger: Slf4jLogger

Contract feignContract: SpringMvcContract

Feign.Builder feignBuilder: HystrixFeign.Builder

可以通过设置 feign.okhttp.enabled:true属性来使用OkHttpClient和ApacheHttpClient,别忘了添加到类路径

Spring Cloud Netflix 不为Feign提供下面的默认属性,但是一样会在应用的上下文中去搜索这些Bean然后创建feign client

Logger.Level

Retryer

ErrorDecoder

Request.Options

Collection

如果你需要一个额外的属性,或者想覆盖一个属性,你可以为每一个FeignClient创建自定义的属性Bean:

@FeignClient(

name = "reddit-service",

url = "${com.deswaef.reddit.url}",

configuration = RedditFeignConfiguration.class

)

@Configuration

public class RedditFeignConfiguration {

public static final int FIVE_SECONDS = 5000;

@Bean

public Logger.Level feignLogger() {

return Logger.Level.FULL;

}

@Bean

public Request.Options options() {

return new Request.Options(FIVE_SECONDS, FIVE_SECONDS);

}

@Bean

public Contract feignContract() {

return new feign.Contract.Default();

}

@Bean

public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {

return new BasicAuthRequestInterceptor("user", "password");

}

}

Feign中不使用Hystrix特性

如果你想在你的RequestInterceptor中使用ThreadLocal绑定变量,你需要在Hystrix中设置thread isolation策略或者disable Hystrix in Feign

# To disable Hystrix in Feign

feign:

hystrix:

enabled: false

# To set thread isolation to SEMAPHORE

hystrix:

command:

default:

execution:

isolation:

strategy: SEMAPHORE

Note

if this configuration class is on the component scan path, it'll be also picked up as general configuration. This means that a configuration class like this, when also scanned by our automatic component scan, will override all of the beans for each and every FeignClient, not just the one which defined it as configuration.

也就是说,要是被 automatic component扫描到了,所有的FeignClient都会按照这个class的配置项去生效,而不是仅仅configuration = RedditFeignConfiguration.class 这个显示声明的接口,

As a result, you should place it inside a package that isn't a candidate for a component scan

不要放在能被扫描到的包中。

最简单的做法,就是不要标记 @Configuration 注释。

手动调用Feign

两个示例:

@Import(FeignClientsConfiguration.class)

class FooController {

private FooClient fooClient;

private FooClient adminClient;

@Autowired

public FooController(

Decoder decoder, Encoder encoder, Client client) {

this.fooClient = Feign.builder().client(client)

.encoder(encoder)

.decoder(decoder)

.requestInterceptor(new BasicAuthRequestInterceptor("user", "user"))

.target(FooClient.class, "http://PROD-SVC");

this.adminClient = Feign.builder().client(client)

.encoder(encoder)

.decoder(decoder)

.requestInterceptor(new BasicAuthRequestInterceptor("admin", "admin"))

.target(FooClient.class, "http://PROD-SVC");

}

}

## In the above example FeignClientsConfiguration.class is the default configuration provided by Spring Cloud Netflix.

interface GitHub {

class Repository {

String name;

}

class Contributor {

String login;

}

@RequestLine("GET /users/{username}/repos?sort=full_name")

List repos(@Param("username") String owner);

@RequestLine("GET /repos/{owner}/{repo}/contributors")

List contributors(@Param("owner") String owner, @Param("repo") String repo);

/** Lists all contributors for all repos owned by a user. */

default List contributors(String owner) {

return repos(owner).stream().flatMap(repo -> contributors(owner, repo.name).stream()).map(c -> c.login)

.distinct().collect(Collectors.toList());

}

static GitHub connect() {

Decoder decoder = new GsonDecoder();

return Feign.builder().decoder(decoder).errorDecoder(new GitHubErrorDecoder(decoder))

.logger(new Logger.ErrorLogger()).logLevel(Logger.Level.BASIC)

.target(GitHub.class, "https://api.github.com");

}

}

Feign Hystrix Support

1、Hystrix 在 classpath中且feign.hystrix.enabled=true, Feign 包裹的的所有方法都会自带断路器(circuit breaker)

2、在方法中返回com.netflix.hystrix.HystrixCommand也是可以支持Hystrix特性 : This lets you use reactive patterns (with a call to .toObservable() or .observe() or asynchronous use (with a call to .queue()).

Note:Prior to the Spring Cloud Dalston release, if Hystrix was on the classpath Feign would have wrapped all methods in a circuit breaker by default. This default behavior was changed in Spring Cloud Dalston in favor for an opt-in approach.

在单独的 Feign client中禁止Hystrix特性,可以创建一个Feign.Builder with the "prototype" scope

@Configuration

public class FooConfiguration {

@Bean

@Scope("prototype")

public Feign.Builder feignBuilder() {

return Feign.builder();

}

}

Feign Hystrix Fallbacks

常规的降级方式:

@FeignClient(name = "hello", fallback = HystrixClientFallback.class)

protected interface HystrixClient {

@RequestMapping(method = RequestMethod.GET, value = "/hello")

Hello iFailSometimes();

}

static class HystrixClientFallback implements HystrixClient {

@Override

public Hello iFailSometimes() {

return new Hello("fallback");

}

}

如果想要在测试的时候触发降级操作,可以使用fallbackFactory

@FeignClient(name = "hello", fallbackFactory = HystrixClientFallbackFactory.class)

protected interface HystrixClient {

@RequestMapping(method = RequestMethod.GET, value = "/hello")

Hello iFailSometimes();

}

@Component

static class HystrixClientFallbackFactory implements FallbackFactory {

@Override

public HystrixClient create(Throwable cause) {

return new HystrixClientWithFallBackFactory() {

@Override

public Hello iFailSometimes() {

return new Hello("fallback; reason was: " + cause.getMessage());

}

};

}

}

Note:There is a limitation with the implementation of fallbacks in Feign and how Hystrix fallbacks work.

Fallbacks are currently not supported for methods that return com.netflix.hystrix.HystrixCommand and rx.Observable.

通过接口实现的方式去实现降级存在一些局限性。

Fallbacks 当前不支持 在方法中返回com.netflix.hystrix.HystrixCommand and rx.Observable.的情况。

Feign and @Primary

When using Feign with Hystrix fallbacks, there are multiple beans in the ApplicationContext of the same type. This will cause @Autowired to not work because there isn’t exactly one bean, or one marked as primary. To work around this, Spring Cloud Netflix marks all Feign instances as @Primary, so Spring Framework will know which bean to inject. In some cases, this may not be desirable. To turn off this behavior set the primary attribute of @FeignClient to false.

@FeignClient(name = "hello", primary = false)

public interface HelloClient {

// methods here

}

Feign request/response compression

You may consider enabling the request or response GZIP compression for your Feign requests. You can do this by enabling one of the properties:

feign.compression.request.enabled=true

feign.compression.response.enabled=true

Feign request compression gives you settings similar to what you may set for your web server:

feign.compression.request.enabled=true

feign.compression.request.mime-types=text/xml,application/xml,application/json

feign.compression.request.min-request-size=2048

These properties allow you to be selective about the compressed media types and minimum request threshold length.

Feign logging

A logger is created for each Feign client created. By default the name of the logger is the full class name of the interface used to create the Feign client. Feign logging only responds to the DEBUG level.

application.yml

logging.level.project.user.UserClient: DEBUG

The Logger.Level object that you may configure per client, tells Feign how much to log. Choices are:

NONE, No logging (DEFAULT).

BASIC, Log only the request method and URL and the response status code and execution time.

HEADERS, Log the basic information along with request and response headers.

FULL, Log the headers, body, and metadata for both requests and responses.

For example, the following would set the Logger.Level to FULL:

@Configuration

public class FooConfiguration {

@Bean

Logger.Level feignLoggerLevel() {

return Logger.Level.FULL;

}

}

参考网站

feign扫描_Feign基础入门及特性讲解相关推荐

  1. Python从入门到实战 基础入门视频教程(讲解超细致)-黄勇-专题视频课程

    Python从入门到实战 基础入门视频教程(讲解超细致)-4123人已学习 课程介绍         Python基础入门视频教程:本课程从Python入门到纯Python项目实战.超100以上课时, ...

  2. feign扫描_feign原理+源码解析

    1 架构图. 2 feign的初始化扫包原理. (1)feign使用,是main上的@EnableFeignClients 和 api的@FeignClient(value = "servi ...

  3. 零基础学python书籍-清华大学出版社-图书详情-《零基础入门学习Python》

    前言 Life is short. You need Python. --Bruce Eckel 上边这句话是Python社区的名言,翻译过来就是"人生苦短,我用Python". ...

  4. kafka基础入门_CodingPark编程公园

    文章介绍 本文是kafka基础入门篇,讲解内容包括: 1. 消息队列对比表 2. Kafka概念及特性 3. kafka总体结构 4. kafka各项配置 5. 生产者 6. kafka Broker ...

  5. JAVA基础入门(4)—— 标识符、关键字和字面值

    前言 在上一节中,讲到了JAVA开端的一个HelloWorld小程序,其中对代码以及一些细节的知识点做了阐述.本节将继续对JAVA基础入门知识进行讲解演示,分别对JAVA中的标识符.关键字以及字面值进 ...

  6. Linux基础入门之内外命令讲解篇

    Linux基础入门篇--之内外命令讲解 1.基础命令 命令 使用方法 cat /etc/motd 设置用户成功登录系统后显示的提示信息.比如欢迎语! cat /etc/issue 设置用户成功登录系统 ...

  7. Linux基础入门,简单讲解

    Linux基础入门,简单讲解 涵盖内容:计算机组成与Linux操作系统概论 任务要求:大概了解计算机的主要组成部件,明白计算机磁盘分区方式,常用的计算单元换算以及LINUX是什么.有什么特点即可. 文 ...

  8. FLASH脚本基础入门讲解1

    1.FLASH脚本基础入门讲解.按钮AS的编写.影片剪辑的AS编写 认识"动作"面板 在Flash中,动作脚本的编写,都是在"动作"面板的编辑环境中进行,熟悉& ...

  9. 视频教程-JSON基础入门实战讲解-JavaScript

    JSON基础入门实战讲解 04年进入计算机行业.拥有6年net和php项目开发经验,8年java项目开发经验. 现前端全栈工程师,主攻产品设计,微信开发等. 黄菊华 ¥39.00 立即订阅 扫码下载「 ...

  10. JSON基础入门实战讲解在线视频课程-JSON 使用 JavaScript 语法

    因为 JSON 使用 JavaScript 语法,所以无需额外的软件就能处理 JavaScript 中的 JSON. 微信小程序交流群:111733917 | 微信小程序从0基础到就业的课程:http ...

最新文章

  1. Logstash(二)input、codec插件详解
  2. 杨强:人工智能在企业的落地是一门大学问
  3. 《多处理器编程的艺术》读书笔记(4)--- 自旋锁(1)
  4. VTK修炼之道78:交互与拾取_点拾取
  5. tensorflow与numpy的版本兼容性问题(亲测)
  6. 打破学习的玻璃墙_打破Google背后的创新深度学习
  7. 面试题:为什么局部变量不赋初始值报错
  8. 感觉小轿车要比SUV舒服,为什么很多人还是选择了SUV?
  9. C#对Windows服务组的启动与停止
  10. 测试wcf的http和tcp绑定以及非wcf的命名管道传输文件速度对比
  11. oracle number +1,number number(1)
  12. Linux中进程与线程的概念以及区别
  13. RTS Threshold
  14. aspCms 标签大全
  15. java计算机毕业设计四六级在线考试系统源码+系统+数据库+lw文档+mybatis+运行部署
  16. php更换banner图片,如何替换banner上的图片?
  17. LSMW 批量更改BOM 成本核算标识相关标识 特殊处理
  18. sql数据库习题总集
  19. u-boot:env源码目录分析一
  20. 用U深度启动U盘清除系统登入密码

热门文章

  1. 使用Bitbucket Cloud学习Git
  2. echarts的x轴去掉网格线
  3. linux网络不通检查方法
  4. 谷歌正式放弃与雅虎的广告合作计划
  5. 零基础学习嵌入式C语言要学习什么?
  6. Android jetpack Room数据库(一)基本使用
  7. DSP28335 ecap使用
  8. Wireshark从入门到精通(进阶篇)
  9. 关于‘go list‘ failed with: error obtaining VCS status error obtaining VCS status: exit status 128问题的解决
  10. ps切图技巧、基础工具,使用方法总结