美文网首页
Feign-声明式REST调用

Feign-声明式REST调用

作者: bluexiii | 来源:发表于2017-09-16 09:53 被阅读504次

简介

本文主要介绍如何使用spring-cloud-feign,在项目中使用Feign进行REST调用。

通常我们进行微服务间的REST调用时,一般会使用restTemplate,写起来也比较方便,例如:

ResponseEntity<UserDTO> result = restTemplate.getForEntity(baseurl + "/users?serialNumber=18612341234", UserDTO.class);

ResponseEntity<String> result = restTemplate.exchange(baseurl +  "/users/1715043034165359", HttpMethod.PUT, new HttpEntity(user), String.class);

但RestTemplate这种方式的缺点是代码量略大,且不太直观。

微服务强调跨语言解耦,不提倡以前那种将API部分打包并分发的方式。不同微服务间的业务代码的冗余不可避免。使用Feign,就可以简化Rest客户端这一部分的代码。

引入pom.xml依赖

Spring Boot工程中,直接引入spring-cloud-starter-feign依赖即可。

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-dependencies</artifactId>
      <version>Dalston.SR2</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

<dependencies>
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-feign</artifactId>
  </dependency>
</dependencies>

application.yml配置

新版本的Feign默认是禁用Hystrix的,需要手工配置打开。

feign.hystrix.enabled: true

Feign本身可以与Eureka/Ribbon比较好的配合使用,不需要其它配置,直接使用"应用名"进行调用。

当微服务没有使用Eureka做服务发现时,就需要手工配置Ribbon。例如,当使用marathon-lb时,可以这样配置:

marathon-lb-internal.ribbon.listOfServers: marathon-lb-internal.marathon.mesos

这里指定了一个DNS,当然也可以写死一个或多个IP。

启用EnableFeignClients注解

最简单的,可以在Application.java上,加上这个注解:

@EnableFeignClients

或者,新建一个配置类,指定profile:

@Profile("enable-feign")
@Configuration
@EnableFeignClients(basePackages = {"com.sitech.sdtools"})
public class FeignConfiguration {}

使用配置类+profile的好处是,可以根据不同的环境,非常方便的启用/禁用Feign。
特别是在单元测试时,由于mockito无法对Feign生成的Bean进行Mock,这时就可以在profile中禁用Feign,直接执行Fallback。

另外,需要注意一下,如果配置类的路径不是在根路径,而是在com.foo.bar.config这样的包下,需要加上"basePackages"参数。

解决Bean冲突

我目前的Spring Clound的版本是Dalston.SR2,如果集成了Hystrix,编写Fallback类后会有Bean冲突的问题,貌似是自动生成的@Primary注解无效,具体原因没有深究,可以通过配置解决,示例如下:

@Configuration
@ConditionalOnClass({Feign.class})
public class FeignConfiguration {
    @Bean
    public WebMvcRegistrations feignWebRegistrations() {
        return new WebMvcRegistrationsAdapter() {
            @Override
            public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
                return new FeignFilterRequestMappingHandlerMapping();
            }
        };
    }

    private static class FeignFilterRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
        @Override
        protected boolean isHandler(Class<?> beanType) {
            return super.isHandler(beanType) && (AnnotationUtils.findAnnotation(beanType, FeignClient.class) == null);
        }
    }
}

开启日志

Feign的日志是DEBUG级别,在LogBack中有时需要特别配置一下:

<logger name="com.foo.bar.client" additivity="false" level="debug">
  <appender-ref ref="stdout"/>
</logger>

定义client接口

下面开始,正式进入正题,定义一个接口,并加上@FeignClient注解。

@FeignClient(name = "marathon-lb-internal", fallback = StaticInfoClientFallback.class)
@RequestMapping(value = "/sd/staticinfo")
public interface StaticInfoClient {
    @RequestMapping(value = "/products/{productId}", method = RequestMethod.GET)
    public ProductDTO getProductInfo(@PathVariable("productId") Long productId);
}

可以直接在服务端的Controller层中拷贝代码,稍做修改即可,非常方便。

但请注意:

  1. @PathVariable("productId"),需要显示的指定对应的参数名,不能像SpringMVC一样自动对应。
  2. 目前只能使用@RequestMapping注解,而不能使用@GetMapping

编写fallback类

当调用失败时,会执行fallback类中的逻辑。

@Component
class StaticInfoClientFallback implements StaticInfoClient {
    private static final Logger logger = LoggerFactory.getLogger(TradeInfoClientFallback.class);

    @Override
    public ProductDTO getProductInfo(Long productId) {
        logger.error("StaticInfoClient.getProductInfo 执行失败");

        ProductDTO dto = new ProductDTO();
        dto.setProductId(productId);
        dto.setProductName("产品名称暂时无法获取");
        return dto;
    }
}

注意不要忘记加上@Component

发起REST调用

REST调用也非常简单,一行代码搞定:

ProductDTO productInfo = staticInfoClient.getProductInfo(entity.getProductId());

END

Feign的配置略微复杂,坑也比较多,有一定的学习成本的。但带来的好处理,在使用上即优雅又方便。
与RestTemplate相比,只能说是各有利弊吧,可以酌情选择。

相关文章

  • Feign-声明式REST调用

    简介 本文主要介绍如何使用spring-cloud-feign,在项目中使用Feign进行REST调用。 通常我们...

  • SpringCloud | 3.服务消费者(Feign声明式RE

    使用Feign声明式REST调用 Feign简介 Feign 是一个声明web服务客户端,这便得编写web服务客户...

  • Spring MVC项目使用Feign声明式服务调用

    Spring MVC项目使用Feign声明式服务调用 什么是声明式服务调用? 拆分成声明式服务调用 什么声明式? ...

  • 使用feign实现声明式的rest调用

    pom文件导入feign依赖 新建一个接口类 @FeignClient(value="teacher")value...

  • 声明式调用---Feign

    Feign:Feign是一种声明式、模板化的HTTP客户端。 用我的理解来说,Feign的功能类似dubbo暴露服...

  • Feign——声明式调用

    1 Feign简介 Feign是Netflix开发的声明式、模板化的HTTP客户端,在Spring Cloud中,...

  • 声明式调用Feign

    上一章中讲解了如何使用RestTemplate来消费服务,如何结合Ribbon在消费服务时做负载均衡。本章将讲解F...

  • 浅谈Feign

    Feign Declarative REST Client: Feign Feign是一个声明式的Web服务客户端...

  • open feign 使用备忘

    一、原理 声明式Rest Client 是对Ribbon的封装(间接对httpclient或okhttp的封装) ...

  • Feigh声明式服务调用

    在RPC框架中,服务调用一般是服务的暴露接口,并提供客户端API,客户端在添加依赖后,即可像本地方法一样调用远程服...

网友评论

      本文标题:Feign-声明式REST调用

      本文链接:https://www.haomeiwen.com/subject/dijysxtx.html