Feign详解1

目录

1. 什么是 Feign

2. Feign 解决了什么问题

1). 引入 maven 依赖

2). 定义查询请求中的参数的封装类

3). 定义接口

4). 测试类

3. Feign 声明式注解


1. 什么是 Feign

Feign 的英文表意为“假装,伪装,变形”, 是一个 Http 请求调用的轻量级框架,可以以 Java 接口注解的方式调用 Http 请求,而不用像 Java 中通过封装 HTTP 请求报文的方式直接调用。

Feign 通过处理注解,将请求模板化,当实际调用的时候,传入参数,根据参数再应用到请求上,进而转化成真正的请求,这种请求相对而言比较直观。

Feign 被广泛应用在 Spring Cloud 的解决方案中,是学习基于 Spring Cloud 微服务架构不可或缺的重要组件。

Feign 开源项目地址:https://github.com/OpenFeign/feign

2. Feign 解决了什么问题

Feign 封装 HTTP 调用流程,面向接口编程。

Feign 本身很简单,但做了大量的适配工作,这也是这个框架存在的意义。

在服务调用的场景中,我们经常调用基于 Http 协议的服务,而我们经常使用到的框架可能有HttpURLConnection、Apache HttpComponnets、OkHttp3 、Netty 等等,这些框架在基于自身的专注点提供了自身特性。而从角色划分上来看,他们的职能是一致的提供 Http 调用服务。具体流程如下:

总结: 根据上图的分析可知:要实现 Feign 客户端,主要是将 Method 方法的参数解析成 Http 请求的请求行、请求行、请求体,然后使用 HttpClient 发送请求。但为了实现这些设想,要解决以下问题:

  • REST 声明式规范有以下几种:Feign、JAX-RS 1/2、Spring Web MVC 都需要进行适配。这几种声明式注解的适配接口是 feign.Contract
  •  Http 客户端有 JDK 自带的 HttpURLConnection、Apache HttpComponnets、OkHttp3 、Netty 等,需要适配。这几种客户端的适配接口是 feign.Client
  • 支持负载均衡与熔断。负载均衡 Ribbon 是对 feign.Client 进行包装。熔断 Hystrix 在 HystrixFeign 中自定义 InvocationHandlerFactory 的实现,创建 HystrixInvocationHandler,对 method.invoke 请求做拦截。
  • 各种编解码的适配,实现接口 feign.codec.Decoder 和 feign.codec.Encoder

下面我们先跟着官网的示例来做一个入门案例,这个案例的功能是访问github中的openfeign的contributor信息. 

github中的API列表如下:    https://api.github.com/

我们将访问:        repository_url: "https://api.github.com/repos/{owner}/{repo}   这个接口, 它里面要加入两个参数  owner, repo, 构成访问:  https://api.github.com/repos/OpenFeign/feign/contributors. 访问后的结果页:

 

1). 引入 maven 依赖

 <dependencies>
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-core</artifactId>
            <version>10.4.0</version>
        </dependency>
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-gson</artifactId>
            <version>10.4.0</version>
        </dependency>
</dependencies>

2). 定义查询请求中的参数的封装类

//两个参数, 用于  请求的地址:   https://api.github.com/repos/OpenFeign/feign/contributors 返回值的封装
//
public class Contributor
{
        String login;
        int contributions;
        int id;
        String node_id;
        String avatar_url;
        String gravatar_id;
        String url;
        String html_url;
        String followers_url;
//        String following_url;
//        String gists_url;
//        String starred_url;
//        String subscriptions_url;
//        String organizations_url;
//        String repos_url;
//        String events_url;
//        String received_events_url;
//        String type;


        @Override
        public String toString() {
                return "Contributor{" +
                        "login='" + login + '\'' +
                        ", contributions=" + contributions +
                        ", id=" + id +
                        ", node_id='" + node_id + '\'' +
                        ", avatar_url='" + avatar_url + '\'' +
                        ", gravatar_id='" + gravatar_id + '\'' +
                        ", url='" + url + '\'' +
                        ", html_url='" + html_url + '\'' +
                        ", followers_url='" + followers_url + '\'' +
                        '}';
        }
}

这个类对应 请求地址:  https://api.github.com/repos/OpenFeign/feign/contributors  的返回结果的封装

3). 定义接口

public interface GitHub {
    // 传入的参数后可以拼接成url: https://api.github.com/repos/OpenFeign/feign/contributors
    @RequestLine("GET /repos/{owner}/{repo}/contributors")
    List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repo);
}

4). 测试类

public class MyApp {
    public static void main(String[] args) {
        GitHub github = Feign.builder()
                .decoder(new GsonDecoder())
                .target(GitHub.class, "https://api.github.com");

        List<Contributor> contributors = github.contributors("OpenFeign", "feign");
        for (Contributor contributor : contributors) {
            System.out.println(contributor);
        }
    }
}

小结: Feign.target() 实际上是创建了一个 GitHub 的动态代理。通过这个代理来访问url,获取到结果后,包装成对象返回. 

3. Feign 声明式注解

Feign 通过 Contract 接口将方法上标注的注解解析成 MethodMetadata,最终将参数解析成 Http 请求的请求行、请求行、请求体,然后使用 HttpClient 发送请求。

AnnotationInterface TargetUsage
@RequestLineMethod定义HttpMethod 和 UriTemplate. UriTemplate 中使用{} 包裹的表达式,可以通过在方法参数上使用@Param 自动注入
@ParamParameter定义模板变量,模板变量的值可以使用名称的方式使用模板注入解析
@HeadersMethod, Type定义头部模板变量,使用@Param 注解提供参数值的注入。如果该注解添加在接口类上,则所有的请求都会携带对应的Header信息;如果在方法上,则只会添加到对应的方法请求上
@QueryMapParameter定义一个Map或 POJO,参数值将会被转换成URL上的 query 字符串上
@HeaderMapParameterMap ->Http Headers
@BodyMethodDefines a Template, similar to a UriTemplate and HeaderTemplate, that uses @Param annotated values to resolve the corresponding Expressions.

以上注解的基本使用案例:

public interface FeignService {
  // @Headers
  @RequestLine("GET /api/documents/{contentType}")
  @Headers("Accept: {contentType}")
  String getDocumentByType(@Param("contentType") String type);
  
  // @QueryMap: Map or POJO
  @RequestLine("GET /find")
  V find(@QueryMap Map<String, Object> queryMap);
  @RequestLine("GET /find")
  V find(@QueryMap CustomPojo customPojo);
  
  // @HeaderMap: Map
  @RequestLine("POST /")
  void post(@HeaderMap Map<String, Object> headerMap);
    
  // @Body
  @RequestLine("POST /")
  @Headers("Content-Type: application/xml")
  @Body("<login \"user_name\"=\"{user_name}\" \"password\"=\"{password}\"/>")
  void xml(@Param("user_name") String user, @Param("password") String password);

  @RequestLine("POST /")
  @Headers("Content-Type: application/json")
  @Body("%7B\"user_name\": \"{user_name}\", \"password\": \"{password}\"%7D")
  void json(@Param("user_name") String user, @Param("password") String password);
}

 

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Feign是一个HTTP客户端,它可以将HTTP请求转发到其他微服务。使用Feign可以使得微服务之间的调用更加简单和优雅。下面是使用Feign的详细步骤: 1. 添加依赖 在使用Feign之前,需要先在pom.xml文件中添加Feign的依赖,如下所示: ```xml <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> ``` 2. 创建Feign接口 在使用Feign时,需要先创建一个接口,用于定义需要调用的其他微服务的API。这个接口的方法签名和被调用的微服务的API方法签名必须一致。例如,如果需要调用另一个微服务的getUserInfo方法,那么Feign接口的定义如下所示: ```java @FeignClient(name = "user-service") public interface UserService { @GetMapping("/user/getUserInfo") public UserInfo getUserInfo(@RequestParam("userId") String userId); } ``` 在这个例子中,@FeignClient注解用于指定需要调用的微服务的名称,name属性的值为"user-service",这个值需要和被调用的微服务的spring.application.name属性的值一致。接着,定义了一个getUserInfo方法,这个方法的签名与被调用的微服务的getUserInfo方法的签名一致,使用@GetMapping注解标注请求的路径,这里的路径为"/user/getUserInfo"。最后,定义了一个UserInfo类型的返回值,用于封装被调用的微服务的返回结果。 3. 注入Feign接口 在需要使用Feign调用其他微服务的地方,可以直接注入Feign接口,例如在Service层中注入上面定义的UserService接口: ```java @Service public class UserServiceImpl implements UserService { @Autowired private UserService userService; public UserInfo getUserInfo(String userId) { return userService.getUserInfo(userId); } } ``` 在这个例子中,UserServiceImpl类注入了UserService接口,并且调用了getUserInfo方法。在实际运行时,Feign会根据接口的定义动态生成一个HTTP客户端,并将请求转发到其他微服务。 4. 启用Feign 在使用Feign时,需要在Spring Boot应用程序的启动类上添加@EnableFeignClients注解,如下所示: ```java @SpringBootApplication @EnableFeignClients public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ``` 在这个例子中,@EnableFeignClients注解用于启用Feign客户端。在启用Feign之后,Spring Boot会自动扫描所有标注了@FeignClient注解的接口,并为它们动态生成HTTP客户端。 以上就是使用Feign的详细步骤。使用Feign可以使得微服务之间的调用更加简单和优雅,提高代码的复用性和可维护性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhangyingchengqi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值