什么是Feign,又为什么使用Feign。Feign是一个声明式的Web Service客户端, Feign满足JSR 356规范、满足JAX-RS(Java API for RESTful)规范 ,可以快速地构建具有RESTful风格的网络请求应用。为什么用Feign,在微服务架构中, 庞杂的系统被分成了一个个微小的服务,服务与服务之间是通过HTTP接口的形式对外提供服务,Feign让服务间的调用变得简单。
官方的定义:
Feign is a Java to HTTP client binder inspired by Retrofit, JAXRS-2.0, and WebSocket. Feign's first goal was reducing the complexity of binding Denominator uniformly to HTTP APIs regardless of ReSTfulness.
它具有如下特性:
1. 支持可插拔的注解支持,包括Feign注解和JAX-RS注解
2. 支持可插拔的HTTP编码器和解码器
3. 支持Hystrix和回滚
4. 支持Ribbon的负载均衡
5. 支持HTTP请求和响应的压缩
接下来将通过几个实战的案例讲解Feign的特性,关于Ribbon和Hystrix的部分会在接下来关于RIbbon和Hytrix的文章中整合,此篇文章暂不包括。
1 入门案例,根据FeignClient指定调用URL的方式,根据查询的参数搜索GitHub上的项目信息,下图为正常通过github查询到的关于spring-framework的搜索结果,目前有11395个项目包含spring-framework相关内容
在业务代码中,通过注解@FeignClient,指定要调用URL为https://api.github.com,Service会根据URL和@RequestMapping对应的方法转换成最终的请求地址https://api.github.com/search/repositories?q=spring-framework,然后返回对应的仓库信息,如图1所示:
package com.bruce.sample.demo.service;
import com.bruce.sample.demo.config.HelloFeignServiceConfig;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
/**
* @Author: Bruce
* @Date: 2019/6/20 18:01
* @Version 1.0
*/
@FeignClient(name = "github-client", url = "https://api.github.com", configuration = HelloFeignServiceConfig.class)
public interface HelloFeignService {
@RequestMapping(value = "/search/repositories", method = RequestMethod.GET)
String searchRepo(@RequestParam("q") String queryStr);
}
然后在控制层,将业务通过注解@Autowired注入对应的调用位置,然后启动应用,输入URL:localhost:8010/search/github?string=spring-framework就可以在本地看到调用的结果,完全感知不到这是在调用远程方法。
package com.bruce.sample.demo.controller;
import com.bruce.sample.demo.service.HelloFeignService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* @Author: Bruce
* @Date: 2019/6/20 22:08
* @Version 1.0
*/
@RestController
public class HelloFeignController {
@Autowired
private HelloFeignService helloFeignService;
@GetMapping(value = "/search/github")
public String searchGithubRepoByStr(@RequestParam("string") String queryStr) {
return helloFeignService.searchRepo(queryStr);
}
}
配置文件application.yml
server:
port: 8010
spring:
application:
name: feign-demo
全部代码见我的GitHub:https://github.com/Guilai1990/feigndemo/tree/master/demo
2 Spring Cloud Feign支持对请求和响应进行GZIP压缩,提高通信效率,下面演示开启GZIP压缩案例。
代码如下
package com.bruce.gzipdemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
@EnableFeignClients
@SpringBootApplication
public class GzipdemoApplication {
public static void main(String[] args) {
SpringApplication.run(GzipdemoApplication.class, args);
}
}
package com.bruce.gzipdemo.config;
import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Author: Bruce
* @Date: 2019/6/20 22:13
* @Version 1.0
*/
@Configuration
public class HelloFeignServiceConfig {
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
package com.bruce.gzipdemo.controller;
import com.bruce.gzipdemo.service.HelloFeignService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* @Author: Bruce
* @Date: 2019/6/20 22:08
* @Version 1.0
*/
@RestController
public class HelloFeignController {
@Autowired
private HelloFeignService helloFeignService;
@GetMapping(value = "/search/github")
public ResponseEntity searchGithubRepoByStr(@RequestParam("string") String queryStr) {
return helloFeignService.searchRepo(queryStr);
}
}
package com.bruce.gzipdemo.service;
import com.bruce.gzipdemo.config.HelloFeignServiceConfig;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
/**
* @Author: Bruce
* @Date: 2019/6/20 18:01
* @Version 1.0
*/
@FeignClient(name = "github-client", url = "https://api.github.com", configuration = HelloFeignServiceConfig.class)
public interface HelloFeignService {
@RequestMapping(value = "/search/repositories", method = RequestMethod.GET)
ResponseEntity searchRepo(@RequestParam("q") String queryStr);
}
配置文件application.yml
server:
port: 8010
spring:
application:
name: feign-demo
feign:
compression:
request:
enabled: true
min-request-size: 2048
mime-types: text/xml,appliation/json,application/xml
response:
enabled: true
返回结果如下图
示例代码见我的GitHub: https://github.com/Guilai1990/feigndemo/tree/master/gzipdemo
3 Feign默认使用JDK原生URLConnection发送HTTP请求,没有连接池,对每个地址保持长连接。对于这点,可以通过用Apache的HTTP Client或者okhttp来替换原生的HTTP Client,进行调用调优。
例如使用HTTP Client取代Feign原始的HTTP Client,在配置文件application.yml要添加如下设置,即开启替换设置
feign:
httpclient:
enabled: true
全部代码详见我的github:https://github.com/Guilai1990/feigndemo/tree/master/httpclient
使用okhttp替换原始的HTTP Client,在配置文件application.yml要添加如下设置,即开启替换设置
feign:
httpclient:
enabled: false
okhttp:
enabled: true
全部代码详见我的github:https://github.com/Guilai1990/feigndemo/tree/master/okhttp
4.Feign当然可以和Eureka一起使用,只要配置好Eureka Client和Eureka Server, Eureka具体使用方法见上篇文章Eureka实战篇,全部代码见我的github:
https://github.com/Guilai1990/feigndemo/tree/master/eureka-server
https://github.com/Guilai1990/feigndemo/tree/master/eureka-consumer
https://github.com/Guilai1990/feigndemo/tree/master/eureka-provider
效果如下:
5.Feign还可以上传文件,只需要添加依赖feign-form, feign-form-spring,详细代码见我的代码仓库:
https://github.com/Guilai1990/feigndemo/tree/master/eureka-server
https://github.com/Guilai1990/feigndemo/tree/master/feign-file-server
https://github.com/Guilai1990/feigndemo/tree/master/feign-upload-client
module: feign-file-server, feign-upload-client, eureka-server
效果图如下:
这里需要注意的是Spring Boot 2.X版本整合Swagger会出现404 Not Found错误,因此在代码中添加了如下设置,此处参考了文章解决SpringBoot2.0集成Swagger2访问404的问题
package com.bruce.feignuploadclient.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* @Author: Bruce
* @Date: 2019/6/21 18:13
* @Version 1.0
*/
@Configuration
@EnableWebMvc
public class ApplicationExceptionAdapter extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
registry.addResourceHandler("/swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
效果图如下:
关于Feign的实战就介绍到这里,相信对Feign的功能和特性有了初步了解,接下来会写一篇文章,源码解读Feign组件,来加深对Feign的理解。
参考资料:
解决SpringBoot2.0集成Swagger2访问404的问题