Feign 不做任何要求处理,通过处理表明干系信息天生 Request,并对调用返回的数据进行解码,从而实现 简化 HTTP API 的开拓
如果要利用 Feign,须要创建一个接口并对其添加 Feign 干系表明,其余 Feign 还支持可插拔编码器和解码器,致力于打造一个轻量级 HTTP 客户端
Feign 最早是由 Netflix 公司进行掩护的,后来 Netflix 不再对其进行掩护,终极 Feign 由社区进行掩护,更名为 Openfeign。

找到做事消费者8200项目,修正pom.xml添加依赖
<!--openfeign --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
2.2 主启动类加上表明@EnableFeignClients表明
@EnableFeignClients申明该项目是Feign客户端,扫描对应的feign client。
package com.elio.springcloud;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;import org.springframework.cloud.client.discovery.EnableDiscoveryClient;import org.springframework.cloud.openfeign.EnableFeignClients;@SpringBootApplication(exclude={DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class})@EnableDiscoveryClient@EnableFeignClientspublic class ProductConsumer8200 { public static void main(String[] args){ SpringApplication.run(ProductConsumer8200.class, args); }}
2.3 新增供应者API接口
我们须要集中化管理API,就可以通过接口统一管理,须要新增商品做事的接口类ProductService,并添加@FeignClient(name="springcloud-product-provider")表明,个中name便是我们要访问的微做事的名称。比如getServiceInfo方法中@GetMapping("product/provider/get/info")和做事供应者8100的接口路径是一样的。
package com.elio.springcloud.service;import com.elio.springcloud.dto.Result;import org.springframework.cloud.openfeign.FeignClient;import org.springframework.stereotype.Component;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PathVariable;@Component@FeignClient(name="springcloud-product-provider")public interface ProductService { / 查询 @return / @GetMapping("product/provider/get/info") public Result getServiceInfo(); / 查询 @param id @return / @GetMapping("product/provider/get/{id}") public Result selectById(@PathVariable("id") Long id);}
2.4 修正消费者Controller
现在接口已经封装在了ProductService里面了,因此在消费者Controller,我们不用再通过微做事名加地址去访问了,修正后的Controller如下
package com.elio.springcloud.controller;import com.elio.springcloud.dto.Result;import com.elio.springcloud.service.ProductService;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RestController;import org.springframework.web.client.RestTemplate;import javax.annotation.Resource;@RestControllerpublic class ProductConsumerController { @Resource RestTemplate restTemplate; @Resource ProductService productService; //public static String url = "http://localhost:8100/"; public static String url = "http://springcloud-product-provider/"; / 查询 @return / @GetMapping("product/consumer/get/info") public Result getServiceInfo(){ return productService.getServiceInfo(); /return new Result(200, "查询成功", restTemplate.getForObject(url+"product/provider/get/info", Result.class));/ } / 查询 @param id @return / @GetMapping("product/consumer/get/{id}") public Result selectById(@PathVariable("id") Long id){ return productService.selectById(id); / return new Result(200, "查询成功", restTemplate.getForObject(url+"product/provider/get/"+id, Result.class));/ }}
2.5 测试
现在我们已经配置好了消费端通过OpenFeign调用远程接口,接下来便是重启消费端做事8200,重启后,浏览器访问消费者API
访问的8100做事
访问的8101做事
3 OpenFeign超时掌握ReadTimeout: 值的是建立链接所用的韶光,适用于网络状况正常的情形下, 两端链接所用的韶光
ConectTimeout: 指的是建立链接后从做事器读取可用资源所用的韶光
openFeign设置超时时间非常大略,只须要在配置文件中配置,如下:
feign: client: config: ## default 设置的全局超时时间,指定做事名称可以设置单个做事的超时时间 default: connectTimeout: 1000 readTimeout: 1000
4 OpenFeign日志打印功能
为每个创建的 Feign 客户端创建一个记录器。默认情形下,记录器的名称是用于创建 Feign 客户真个接口的完全类名。日志记录仅相应级别:DEBUG。
openFeign的日志级别如下:
NONE:默认的,不显示任何日志;
BASIC:仅记录要求方法、URL、相应状态码及实行韶光;
HEADERS:除了BASIC中定义的信息之外,还有要乞降相应的头信息;
FULL:除了HEADERS中定义的信息之外,还有要乞降相应的正文及元数据。
配置办法:
配置文件application.yml:logging.level.project.user.UserClient: DEBUG
2.自定义一个配置类,在个中设置日志级别
@Configurationpublic class FooConfiguration { @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; }}
5 对@RefreshScope支持
如果启用了 Feign 客户端刷新,则利用以下命令创建每个 Feign 客户端:
feign.Request.Options作为刷新范围的 Bean。这意味着像connectTimeout and readTimeout 等属性可以针对任何 Feign 客户端实例刷新。在 下换行的网址org.springframework.cloud.openfeign.RefreshableUrl。这意味着 Feign 客户真个 URL(如果已定义)spring.cloud.openfeign.client.config.{feignName}.url 属性,可以针对任何 Feign 客户端实例刷新。可以通过 刷新这些属性。POST /actuator/refresh
默认情形下,Feign 客户端中的刷新行为处于禁用状态。利用以下属性启用刷新行为:
spring.cloud.openfeign.client.refresh-enabled=true
6 假要求/相应压缩
您可以考虑为您的启用要求或相应 GZIP 压缩 佯装要求。您可以通过启用以下属性之一来实行此操作:
spring.cloud.openfeign.compression.request.enabled=truespring.cloud.openfeign.compression.response.enabled=true
假要求压缩为您供应的设置类似于您可能为 Web 做事器设置的设置:
spring.cloud.openfeign.compression.request.enabled=truespring.cloud.openfeign.compression.request.mime-types=text/xml,application/xml,application/jsonspring.cloud.openfeign.compression.request.min-request-size=2048
这些属性许可您选择压缩媒体类型和最小要求阈值长度。
7 Feign Spring Cloud CircuitBreaker FallbacksSpring Cloud CircuitBreaker支持回退的观点:当链路断开或涌现缺点时实行的默认代码路径。要为给定的@FeignClient启用回退,请将回退属性设置为实现回退的类名。您还须要将您的实现声明为Springbean:
@FeignClient(name = "test", url = "http://localhost:${server.port}/", fallback = Fallback.class) protected interface TestClient { @RequestMapping(method = RequestMethod.GET, value = "/hello") Hello getHello(); @RequestMapping(method = RequestMethod.GET, value = "/hellonotfound") String getException(); } @Component static class Fallback implements TestClient { @Override public Hello getHello() { throw new NoFallbackAvailableException("Boom!", new RuntimeException()); } @Override public String getException() { return "Fixed response"; } }
如果须要访问导致回退触发的缘故原由,可以在@FeignClient中利用fallbackFactory属性:
@FeignClient(name = "testClientWithFactory", url = "http://localhost:${server.port}/", fallbackFactory = TestFallbackFactory.class) protected interface TestClientWithFactory { @RequestMapping(method = RequestMethod.GET, value = "/hello") Hello getHello(); @RequestMapping(method = RequestMethod.GET, value = "/hellonotfound") String getException(); } @Component static class TestFallbackFactory implements FallbackFactory<FallbackWithFactory> { @Override public FallbackWithFactory create(Throwable cause) { return new FallbackWithFactory(); } } static class FallbackWithFactory implements TestClientWithFactory { @Override public Hello getHello() { throw new NoFallbackAvailableException("Boom!", new RuntimeException()); } @Override public String getException() { return "Fixed response"; } }
8 Feign and @Primary
当将Feign与Spring Cloud CircuitBreaker回退一起利用时,ApplicationContext中存在多个相同类型的bean。这将导致@Autowired无法事情,由于没有确切的一个bean,或者一个被标记为primary。为理解决这个问题,Spring Cloud OpenFeign将所有Feign实例标记为@Primary,这样Spring Framework就会知道要注入哪个bean。在某些情形下,这可能是不可取的。若要关闭此行为,请将@FeignClient的主属性设置为false:
@FeignClient(name = "hello", primary = false)public interface HelloClient { // methods here}
9 Feign Caching
如果利用@EnableCaching annotation,则会创建并注册CachingCapability bean,以便您的Feign客户端在其接口上识别@Cacheannotations:
public interface DemoClient { @GetMapping("/demo/{filterParam}") @Cacheable(cacheNames = "demo-cache", key = "#keyParam") String demoEndpoint(String keyParam, @PathVariable String filterParam);}
您也可以通过属性spring.cloud.openfacy.cache.enabled=false禁用该功能。
10 Fegin事情事理在展开讲解事情事理前, 首先捋一下上文中, 我们完成 Feign 调用前所进行的操作:
添加了 Spring Cloud OpenFeign 的依赖在 SpringBoot 启动类上添加了表明 @EnableFeignCleints按照 Feign 的规则定义接口 DemoService, 添加@FeignClient 表明在须要利用 Feign 接口 DemoService 的地方, 直策应用@Autowire 进行注入利用接口完成对做事真个调用可以根据上面利用 Feign 的步骤大致预测出整体的事情流程:
SpringBoot 运用启动时, 由针对 @EnableFeignClient 这一表明的处理逻辑触发程序扫描 classPath中所有被@FeignClient 表明的类, 这里以 DemoService 为例, 将这些类解析为 BeanDefinition 注册到 Spring 容器中Sping 容器在为某些用的 Feign 接口的 Bean 注入 DemoService 时, Spring 会考试测验从容器中查找 DemoService 的实现类由于我们从来没有编写过 DemoService 的实现类, 上面步骤获取到的 DemoService 的实现类一定是 feign 框架通过扩展 spring 的 Bean 处理逻辑, 为 DemoService 创建一个动态接口代理工具, 这里我们将其称为 DemoServiceProxy 注册到spring 容器中。Spring 终极在利用到 DemoService 的 Bean 中注入了 DemoServiceProxy 这一实例。当业务要求真实发生时, 对付 DemoService 的调用被统一转发到了由 Feign 框架实现的 InvocationHandler 中, InvocationHandler 卖力将接口中的入参转换为 HTTP 的形式, 发到做事端, 末了再解析 HTTP 相应, 将结果转换为 Java 工具, 予以返回。上面全体流程可以进一步简化理解为:
我们定义的接口 DemoService 由于添加了表明 @FeignClient, 终极产生了一个虚假的实现类代理利用这个接口的地方, 终极拿到的都是一个假的代理实现类 DemoServiceProxy所有发生在 DemoServiceProxy 上的调用, 都被转交给 Feign 框架, 翻译成 HTTP 的形式发送出去, 并得到返回结果, 再翻译回接口定义的返回值形式。以是不难创造, Feign 的核心实现事理便是java 原生支持的基于接口的动态代理。
大略总结事情事理如下:
通过 @EnableFeignCleints 触发 Spring 运用程序对 classpath 中 @FeignClient 润色类的扫描解析到 @FeignClient 润色类后, Feign 框架通过扩展 Spring Bean Deifinition 的注册逻辑, 终极注册一个 FeignClientFacotoryBean 进入 Spring 容器Spring 容器在初始化其他用到 @FeignClient 接口的类时, 得到的是 FeignClientFacotryBean 产生的一个代理工具 Proxy.基于 java 原生的动态代理机制, 针对 Proxy 的调用, 都会被统一转发给 Feign 框架所定义的一个 InvocationHandler , 由该 Handler 完成后续的 HTTP 转换, 发送, 吸收, 翻译HTTP相应的事情