[Spring Cloud] 4.6 Declarative REST Client:Feign

4.6 Declarative REST Client: Feign

REST客户端:Feign

Feign是一个Web服务的客户端框架。它让Web服务的客户端开发变得更容易。 只须要使用Feign建立一个接口加上一个注解就好了。Feign和JAX-RS提供一整套插件化的注解配置方式。在Feign中还可使用插件化的编码器和解码器。java

Spring Cloud 还提供一个HttpMessageConverters,这样当使用Spring Web环境时,就能够支持Spring MVC。 在使用Feign时,Spring Cloud还能够整合Ribbon和Eureka,为http客户端提供负载均衡的能力。git

4.6.1 How to Include Feign 如何引入Feign

在工程中引入Feign只须要引入依赖就行:group :org.springframework.cloud artifact id : spring-cloud-starter-feign。详情见Spring Cloud相关文档github

例如:web

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

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

}

StoreClient.javaspring

@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中使用一个字符串(例子中的"stores")来指定客户端名字,这个名字也将被用于一个Ribbon负载均衡器。 还能够配置url属性来指定URL。 在Spring容器中会使用全限定名做为这个Bean的名称。一样,能够经过name属性进行自定义。 在上例中,经过@Qualifier("storesFeignClient")就能够引用到这个Bean。 若是须要改变默认引用名称,能够在@FeignClient中配置qualifier属性。apache

Ribbon客户端将会查找"stores"服务的物理地址。 若是是一个Eureka客户端应用,那么将会自动注册到Eureka中。 若是不想使用Eureka,能够简单的配置一个服务列表,手动指定服务。json

4.6.2 Overriding Feign Defaults 覆盖Feign默认配置

Spring Cloud 的 Feign有一个核心概念,那就是客户端命名。每个Feign客户端都是集群中一组@FeignClient标记的可用服务区域中的一部分。app

Spring Cloud会为每个命名的Feign客户端中的FeignClientsConfiguration建立一个新的ApplicationContext。 这其中会包括一个feign.Decoder,一个feign.Encoder,以及一个feign.Contract负载均衡

Spring Cloud运行开发者经过@FeignClient对Feign客户端进行彻底的控制。例如:框架

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

在这个例子中,客户端使用一个自定义的FooConfiguration整合到FeignClientsConfiguration的配置过程。

警告:

须要确保FooConfiguration不会被@Configuration或者@ComponentScan扫描到,不然,就会被全部@FeignClient共享了(自动注入)。若是使用@ComponentScan或者@SpringBootApplication时,也须要避免FooConfiguration被自动扫描。

注意:

serviceId属性已经丢弃,不建议使用,改用name属性进行配置。

警告:

之前使用url属性时,不须要name。如今不行了,name必须指定。

nameurl属性时,可使用占位符进行配置。例如:

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

Spring Cloud Netflix 默认会建立下列Bean

类型 Bean名称 类名 备注
Decoder feignDecoder ResponseEntityDecoder 包装了SpringDecoder
Encoder feignEncoder SpringEncoder
Logger feignLogger Slf4jLogger
Contract feignContract SpringMvcContract
Feign.Builder feignBuilder HystrixFeign.Builder
Client feignClient LoadBalancerFeignClient 若是启用Ribbon则是LoadBalancerFeignClient,不然使用Feign默认客户端

还能够经过feign.okhttp.enabled或者feign.httpclient.enabled来开启OkHttpClientApacheHttpClient,固然前提是classpath中必须有这些相关依赖。

默认状况下,Spring Cloud Netflix不会为Feign提供下列的Bean,可是仍然能够在spring上下文中经过类型找到它们来建立Feign客户端。

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

能够在@FeignClient的配置类中,自行建立这些Bean来订制Feign客户端。例如:

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

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

这个例子中,使用feign.Contract.Default来替换SpringMvcContract,同时加上一个RequestInterceptor

默认配置能够经过@EnableFeignClientsdefaultConfiguration属性来制定。这些配置,会被应用到全部的Feign客户端上。

4.6.3 Creating Feign Clients Manually 手动建立Feign客户端

在某些场景中,经过上述方法,仍是不能获得一个想要的Feign客户端。 那这个时候,就须要本身经过Feign Builder API来手动建立客户端。 下面这个例子就展示了为同一个接口建立两个不一样配置的客户端。

@Import(FeignClientsConfiguration.class)
class FooController {

	private FooClient fooClient;

	private FooClient adminClient;

    @Autowired
	public FooController(
			ResponseEntityDecoder decoder, SpringEncoder 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是服务的客户端请求时标记的名称。

4.6.4 Feign Hystrix Support :Feign断路器

若是在classpath中加入了Hystrix,那默认Feign就会为全部方法都包装上一个断路器。也会返回一个com.netflix.hystrix.HystrixCommand。这就会致使可使用正则匹配(如:调用.toObservable() or .observe())或者异步请求(如:调用.queue())。

若是不想在Feign使用Hystrix,能够配置:feign.hystrix.enabled=false

若是想让每一个客户端都不使用Hystrix,能够在prototype做用域中建立一个普通的Feign.Builder实现。例如:

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

4.6.5 Feign Hystrix Fallbacks : Feign降级

Hystrix中的降级概念:当链路中发生错误是,执行一个默认的代码逻辑。 能够在@FeignClient中配置fallback属性,来开启Feign降级处理。例如:

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

若是想在降级操做中处理抛出的异常,可使用@FeignClientfallbackFactory属性。例如:

@FeignClient(name = "hello", fallbackFactory = HystrixClientFallbackFactory.class)
protected interface HystrixClient {
	@RequestMapping(method = RequestMethod.GET, value = "/hello")
	Hello iFailSometimes();
}

@Component
static class HystrixClientFallbackFactory implements FallbackFactory<HystrixClient> {
	@Override
	public HystrixClient create(Throwable cause) {
		return new HystrixClientWithFallBackFactory() {
			@Override
			public Hello iFailSometimes() {
				return new Hello("fallback; reason was: " + cause.getMessage());
			}
		};
	}
}

警告: Feign的降级操做与Hystrix降级操做对比有一个限制。降级操做,对于方法的返回类型目前还不支持com.netflix.hystrix.HystrixCommandrx.Observable

4.6.6 Feign Inheritance Support 继承

Feign只支持接口层的单继承。能够将一些通用操做抽象成一个基础接口。例如:

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版本中也不支持这种方式(共用接口)。

4.6.7 Feign request/response compression 数据压缩

能够考虑对Feign的request和response开启GZIP压缩处理。能够在配置文件中经过以下配置开启:

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

在web服务中进行更详细的配置:

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

上例中,指定了Media type和压缩的最小大小进行了指定。

4.6.8 Feign logging 日志

对于建立的每一个Feign客户端都会建立一个Logger。默认状况下,使用客户端全类名做为日志名,Feign日志只能设置为DEBUG级别。

application.yml

logging.level.project.user.UserClient: DEBUG

能够为每一个客户端配置一个Logger.Level对象,来告诉Feign如何输出日志。能够选择如下级别:

  • NONE,无日志(默认
  • BASIC,仅输出请求的方法、URL、response status code 以及执行时间
  • HEADERS,带上request和response的header信息
  • FULL,包括requset和response的header,body以及元数据

例如:

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

4.7 External Configuration: Archaius 使用Archaius进行外部扩展配置

Archaius是一个Netflix客户端配置的类库。这个类库能够被用于全部的Netflix OSS组件的配置。Archaius是在Apache Commons Configuration的基础山进行扩展出来的。Archaius容许客户端轮询自动发现配置的改动变化。Archaius经过Dynamic<Type>Property类来处理各类配置属性。

Archaius Example

class ArchaiusTest {
    DynamicStringProperty myprop = DynamicPropertyFactory
            .getInstance()
            .getStringProperty("my.prop");

    void doSomething() {
        OtherClass.someMethod(myprop.get());
    }
}

Archaius有本身的配置文件集以及预先加载机制。Spring应用一般不会直接使用Archaius,而是经过Netflix原生的配置工具进行使用。Spring Cloud提供一个Spring Environment来对Archaius属性进行桥接使用。这样就可让Spring Boot应用能像使用普通配置属性同样使用Archaius。

相关文章
相关标签/搜索