SpringCloud Feign

时间:2022-06-15
本文章向大家介绍SpringCloud Feign,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

版权声明:本文为博主原创文章,未经博主允许不得转载。

声明性REST客户端:Feign

Feign是一个声明式的Web服务客户端。这使得Web服务客户端的写入更加方便 要使用Feign创建一个界面并对其进行注释。它具有可插拔注释支持,包括Feign注释和JAX-RS注释。Feign还支持可插拔编码器和解码器。Spring Cloud添加了对Spring MVC注释的支持,并在Spring Web中使用默认使用的HttpMessageConverters。Spring Cloud集成Ribbon和Eureka以在使用Feign时提供负载均衡的http客户端。

如何包含Feign

要在您的项目中包含Feign,请使用组org.springframework.cloud和工件ID spring-cloud-starter-feign的启动器。有关 使用当前的Spring Cloud发布列表设置构建系统的详细信息,请参阅Spring Cloud项目页面

示例Spring Boot应用程序

@ComponentScan
@EnableAutoConfiguration
@EnableEurekaClient
@EnableFeignClients
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

StoreClient.java

@FeignClient("stores")
public interface StoreClient {
    @RequestMapping(method = RequestMethod.GET, value = "/stores")
    List<Store> getStores();

    @RequestMapping(method = RequestMethod.POST, value = "/stores/{storeId}", consumes = "application/json")
    Store update(@PathVariable("storeId") Long storeId, Store store);
}

@FeignClient注释中,String值(以上“存储”)是一个任意的客户端名称,用于创建Ribbon负载平衡器(有关Ribbon支持的详细信息,请参阅下文))。您还可以使用url属性(绝对值或只是主机名)指定URL。应用程序上下文中的bean的名称是该接口的完全限定名称。要指定自己的别名值,您可以使用@FeignClient注释的qualifier值。

以上的Ribbon客户端将要发现“商店”服务的物理地址。如果您的应用程序是Eureka客户端,那么它将解决Eureka服务注册表中的服务。如果您不想使用Eureka,您可以简单地配置外部配置中的服务器列表(例如,参见 上文)。

覆盖Feign默认值

Spring Cloud的Feign支持中的一个中心概念就是命名的客户端。每个假装客户端是组合的组合的一部分,它们一起工作以按需联系远程服务器,并且该集合具有您将其作为应用程序开发人员使用@FeignClient注释的名称。Spring Cloud使用FeignClientsConfiguration为每个命名的客户端根据需要创建一个新的集合ApplicationContext。这包含(其中包括)feign.Decoderfeign.Encoderfeign.Contract

Spring Cloud可以通过使用@FeignClient声明其他配置(位于FeignClientsConfiguration之上)来完全控制假客户端。例:

@FeignClient(name = "stores", configuration = FooConfiguration.class)
public interface StoreClient {
    //..
}

在这种情况下,客户端由FeignClientsConfiguration中的组件与FooConfiguration中的任何组件组成(后者将覆盖前者)。

注意

FooConfiguration不需要使用@Configuration注释。但是,如果是,则请注意将其从任何@ComponentScan中排除,否则将包含此配置,因为它将成为feign.Decoder,feign.Encoder,feign.Contract等的默认来源,指定时。这可以通过将其放置在任何@ComponentScan或@SpringBootApplication的单独的不重叠的包中,或者可以在@ComponentScan中明确排除。

注意

serviceId属性现在已被弃用,有利于name属性。

警告

以前,使用url属性,不需要name属性。现在需要使用name。

nameurl属性支持占位符。

@FeignClient(name = "${feign.name}", url = "${feign.url}")
public interface StoreClient {
    //..
}

Spring Cloud Netflix默认为feign(BeanType beanName:ClassName)提供以下bean:

  • Decoder feignDecoder:ResponseEntityDecoder(其中包含SpringDecoder
  • Encoder feignEncoder:SpringEncoder
  • Logger feignLogger:Slf4jLogger
  • Contract feignContract:SpringMvcContract
  • Feign.Builder feignBuilder:HystrixFeign.Builder
  • Client feignClient:如果Ribbon被启用,它是一个LoadBalancerFeignClient,否则使用默认的feign客户端。

可以通过将feign.okhttp.enabledfeign.httpclient.enabled设置为true,并将它们放在类路径上来使用OkHttpClient和ApacheHttpClient feign客户端。

Spring Cloud Netflix 默认情况下提供以下bean,但是仍然从应用程序上下文中查找这些类型的bean以创建假客户端:

  • Logger.Level
  • Retryer
  • ErrorDecoder
  • Request.Options
  • Collection<RequestInterceptor>
  • SetterFactory

创建其中一个类型的bean并将其放置在@FeignClient配置(例如上面的FooConfiguration)中)允许您覆盖所描述的每个bean。例:

@Configuration
public class FooConfiguration {
    @Bean
    public Contract feignContract() {
        return new feign.Contract.Default();
    }

    @Bean
    public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
        return new BasicAuthRequestInterceptor("user", "password");
    }
}

这将SpringMvcContract替换为feign.Contract.Default,并将RequestInterceptor添加到RequestInterceptor的集合中。

可以在@EnableFeignClients属性defaultConfiguration中以与上述相似的方式指定默认配置。不同之处在于,此配置将适用于所有假客户端。

注意

如果您需要在RequestInterceptor`s you will need to either set the thread isolation strategy for Hystrix to `SEMAPHORE中使用ThreadLocal绑定变量或在Feign中禁用Hystrix。

application.yml

# To disable Hystrix in Feign
feign:
  hystrix:
    enabled: false

# To set thread isolation to SEMAPHORE
hystrix:
  command:
    default:
      execution:
        isolation:
          strategy: SEMAPHORE

手动创建Feign客户端

在某些情况下,可能需要以上述方法不可能自定义您的Feign客户端。在这种情况下,您可以使用Feign Builder API创建客户端 。下面是一个创建两个具有相同接口的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");
    }
}

注意

在上面的例子中,FeignClientsConfiguration.class是由Spring Cloud Netflix提供的默认配置。

注意

PROD-SVC是客户端将要求的服务的名称。

Feign Hystrix支持

如果Hystrix在类路径和feign.hystrix.enabled=true上,则Feign将使用断路器包装所有方法。还可以返回com.netflix.hystrix.HystrixCommand。这样可以使用无效模式(调用.toObservable().observe()或异步使用(调用.queue()))。

要在每个客户端基础上禁用Hystrix支持,使用“prototype”范围创建一个vanilla Feign.Builder,例如:

<span style="color:rgba(0, 0, 0, 0.8)"><span style="color:rgba(0, 0, 0, 0.9)"><code class="language-java">@Configuration
public class FooConfiguration {
    @Bean
	@Scope("prototype")
	public Feign.Builder feignBuilder() {
		return Feign.builder();
	}
}</code></span></span>

警告

在Spring Cloud达尔斯顿发布之前,如果Hystrix在类路径Feign中,默认情况下将所有方法都封装在断路器中。这种默认行为在Spring Cloud达尔斯顿更改了赞成选择加入的方式。

Feign Hystrix回退

Hystrix支持回退的概念:当电路打开或出现错误时执行的默认代码路径。要为给定的@FeignClient启用回退,请将fallback属性设置为实现回退的类名。

@Configuration
public class FooConfiguration {
    @Bean
	@Scope("prototype")
	public Feign.Builder feignBuilder() {
		return Feign.builder();
	}
}

如果需要访问导致回退触发的原因,可以使用@FeignClient内的fallbackFactory属性。

@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");
    }
}

警告

在Feign中执行回退以及如何执行Hystrix回退是有限制的。当前返回com.netflix.hystrix.HystrixCommand和rx.Observable的方法目前不支持回退。

Feign和@Primary

当使用Feign与Hystrix回退时,在同一类型的ApplicationContext中有多个bean。这将导致@Autowired不起作用,因为没有一个bean,或者标记为主。要解决这个问题,Spring Cloud Netflix将所有Feign实例标记为@Primary,因此Spring Framework将知道要注入的bean。在某些情况下,这可能是不可取的。要关闭此行为,将@FeignClientprimary属性设置为false。

@FeignClient(name = "hello", primary = false)
public interface HelloClient {
	// methods here
}

Feign继承支持

Feign通过单继承接口支持样板apis。这样就可以将常用操作分成方便的基本界面。

UserService.java

public interface UserService {

    @RequestMapping(method = RequestMethod.GET, value ="/users/{id}")
    User getUser(@PathVariable("id") long id);
}

UserResource.java

@RestController
public class UserResource implements UserService {

}

UserClient.java

package project.user;

@FeignClient("users")
public interface UserClient extends UserService {

}

注意

通常不建议在服务器和客户端之间共享接口。它引入紧耦合,并且实际上不能以当前形式的Spring MVC(方法参数映射不被继承)起作用。

Feign请求/响应压缩

您可以考虑启用针对您的Feign请求的请求或响应GZIP压缩。您可以通过启用其中一个属性来执行此操作:

feign.compression.request.enabled=true
feign.compression.response.enabled=true

Feign请求压缩为您提供与您为Web服务器设置的设置类似的设置:

feign.compression.request.enabled=true
feign.compression.request.mime-types=text/xml,application/xml,application/json
feign.compression.request.min-request-size=2048

这些属性可以让您对压缩介质类型和最小请求阈值长度有选择性。

Feign日志记录

为每个创建的Feign客户端创建一个记录器。默认情况下,记录器的名称是用于创建Feign客户端的接口的完整类名。Feign日志记录仅响应DEBUG级别。

application.yml

logging.level.project.user.UserClient: DEBUG

您可以为每个客户端配置的Logger.Level对象告诉Feign记录多少。选择是:

  • NONE,无记录(DEFAULT)。
  • BASIC,只记录请求方法和URL以及响应状态代码和执行时间。
  • HEADERS,记录基本信息以及请求和响应头。
  • FULL,记录请求和响应的头文件,正文和元数据。

例如,以下将Logger.Level设置为FULL

@Configuration
public class FooConfiguration {
    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}