Feign概述
Feign作为一个声明式的REST客户端,能让REST调用更加简洁。Feign提供了HTTP请求的模板,通过编写简单的接口和插入注解,就可以定义好HTTP请求的参数、格式、地址等信息。Feign会完全代理http请求,我们只需要像调用方法一样就可以完成服务请求及相关处理。Spring Cloud对Feign进行了封装,使其支持Spring MVC标准注解和HttpMessageConverters。Feign可以与Eureka和Ribbon组合使用以支持负载均衡。
使用Feign调用服务接口
-
添加项目依赖
<!--添加Feign依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency><!--添加Eureka依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
<version>1.4.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>1.4.0.RELEASE</version>
</dependency>
- 主程序入口(basePackages配置FeignClient包名。clientService 与 controller 必须都在这个包下)
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(basePackages = {"com.mr"})
@ComponentScan("com.mr")
public class MsConsumerFeignApplication80 {
public static void main(String[] args) {
SpringApplication.run(MsConsumerFeignApplication80.class, args);
}
}
-
Feign客户端
- 使用@FeignClient注解配置服务提供者,value值为服务提供者应用名。
- 使用@GetMapping配置服务提供者提供服务方法url。
@FeignClient(value = "MS-PROVIDER")
public interface DeptClientService {
@RequestMapping(value = "/api/dept/getById", method = RequestMethod.POST)
Map<String,Object> getById(@RequestParam("id") Integer id);
@RequestMapping("/api/dept/save")
Map<String,Object> save(Dept dept);
@RequestMapping("/api/dept/list")
Map<String,Object> list();
}
-
Feign配置文件
server:
port: 80
eureka:
client: #客户端注册进eureka服务列表内
service-url:
# defaultZone: http://localhost:7001/eureka
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
instance:
instance-id: ms-consumer # 防止 Eureka web页面报错 ,主机服务名称修改
prefer-ip-address: true # 访问路径可以显示IP地址,(左下角IP显示)
spring:
application:
name: ms-consumer-feign
-
控制器
public class DespConsumerController {
@Autowired
private DeptClientService deptClientService;
@RequestMapping(value = "getById", method = RequestMethod.POST)
public Map<String,Object> getById(@RequestParam Integer id) {
System.out.println(" ================ 8001 ==============");
return deptClientService.getById(id);
}
@RequestMapping(value = "save", method = RequestMethod.GET)
public Map<String,Object> save(@RequestBody Dept dept) {
return deptClientService.save(dept);
}
@RequestMapping(value = "list", method = RequestMethod.GET)
public Map<String,Object> list() {
return deptClientService.list();
}
}
自定义Feign配置
-
日志配置
- 有时候我们碰到bug,如服务提供接口调用失败等,或者想查看接口调用性能,需要配置Feign日志,以此让Feign把操作日志进行输出。
-
Feign日志配置
@Configuration
public class FeignLoggerConfiguration {
@Bean
Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;//完整请求信息 }
}
}
-
日志级别
public static enum Level {
NONE,//不输出日志
BASIC,//只输出请求方法的URL和响应的状态码以及接口执行的时间
HEADERS,//BASIC和请求头信息输出
FULL;//输出完整的请求信息
private Level() { }
}
-
Feign客户端
@RestController
@RequestMapping(value="api/consumer-feign/“, configuration = FeignLoggerConfiguration.class)
public class DespConsumerController {
@Autowired
private DeptClientService deptClientService;
@RequestMapping(value = "getById", method = RequestMethod.POST)
public Map<String,Object> getById(@RequestParam Integer id) {
System.out.println(" ================ 8001 ==============");
return deptClientService.getById(id);
}
@RequestMapping(value = "save", method = RequestMethod.GET)
public Map<String,Object> save(@RequestBody Dept dept) {
return deptClientService.save(dept);
}
@RequestMapping(value = "list", method = RequestMethod.GET)
public Map<String,Object> list() {
return deptClientService.list();
}
}
@FeignClient value为服务提供者应用名,configuration为Feign日志配置类。
-
配置文件配置Feign日志级别
logging:
level:
com:
springlcoud:
feign:
feigndemo:
client:
UserRemoteClient: DEBUG
配置方式为logging.level.Feign客户端完全类名=日志级别(枚举值)
-
契约配置
SpringCloud在Feign的基础上做了扩展,可以让Feign支持SpringMVC注解进行调用。想要在SpringCloud中使用Feign原生注解定义客户端,需要提供默认契约配置。
@Configuration
public class FeignContractConfiguration {
@Bean
public Contract feignContract(){ return new feign.Contract.Default(); }
}
进行了默认契约配置,Feign无法使用SpringMVC注解方式进行服务调用,需要使用Feign原生方式。
-
Basic认证配置
@Configuration
public class FeignBasicAuthConfiguration {
/*** 根据用户名和密码进行基础认证 * @return */
@Bean
public BasicAuthRequestInterceptor basicAuthRequestInterceptor(){
return new BasicAuthRequestInterceptor(userName,passWord);
}
}
-
自定义认证
public class CustomizeFeignBasicAuthRequestInterceptor implements RequestInterceptor {
/**
* 业务逻辑
* @param requestTemplate
*/
@Override
public void apply(RequestTemplate requestTemplate) {
}
}
@Configuration
public class CustomizeFeignConfiguration {
@Bean
public CustomizeFeignBasicAuthRequestInterceptor customizeFeignBasicAuthRequestInterceptor(){
return new CustomizeFeignBasicAuthRequestInterceptor();
}
}
-
超时时间配置
/** * Feign超时时间配置 */
@Configuration
public class OptionsConfiguration {
/** 超时时间配置
* @param connectTimeoutMillis:连接超时时间
* @param readTimeoutMillis :读取超时时间
* @return
*/
@Bean
public Request.Options options(){
return new Request.Options(connectTimeoutMillis,readTimeoutMillis);
}
}
-
重试配置
/** * Feign重试配置*/
@Configuration
public class FeignRetryerConfiguration {
@Bean
public Retryer getDefaultRetryer(){
return new Retryer.Default();
}
@Bean
public Retryer getCustomizeRetryer(){
/**
* @param period:当前请求时间间隔(单位毫秒)
* @param maxPeriod:当前请求最大时间间隔(单位毫秒)
* @param maxAttempts:最多请求次数(包含第一次)
*/
return new Retryer.Default(period,maxPeriod,maxAttempts);
}
}
-
客户端组件配置
Feign默认使用JDK原生URLConnection发送HTTP请求,我们可以使用别的组件替换URLConnection,比如HttpClient,OKHttp。
-
添加OKHttp依赖:
<!--使用okhttp-->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
-
#feign使用okhttp
feign:
httpclient:
enabled: false
okhttp:
enabled: true
-
GZIP压缩配置
开启压缩配置可以有效节约网络资源,提升接口性能,可以通过GZIP配置来压缩数据
#开启请求压缩
feign:
compression:
request:
enabled: true #开启请求压缩
mime-types: text/xml,application/xml,application/json #配置压缩的类型
min-request-size: 2048 #配置压缩大小
response:
enabled: true #开启响应压缩
-
配置发送请求组件不是OKHttp3时,压缩配置生效
目录
@ConditionalOnMissingBean注解表示不包含指定Bean时条件匹配(未启用OKHttp3时进行压缩配置)
-
编码器与解码器配置
Feign中提供了自定义的编码解码器设置,同时也提供了多种编码解码器实现,我们可以用不同的编码解码器来处理数据的传输。
/** * 自定义解码器 */
@Configuration
@EnableConfigurationProperties({FeignClientEncodingProperties.class})
@ConditionalOnClass({Feign.class})
@ConditionalOnBean({Client.class})
@ConditionalOnProperty(value = {"feign.compression.response.enabled"}, matchIfMissing = false)
@ConditionalOnMissingBean(type = {"okhttp3.OkHttpClient"})
@AutoConfigureAfter({FeignAutoConfiguration.class})
public class FeignAcceptGzipEncodingAutoConfiguration {
public FeignAcceptGzipEncodingAutoConfiguration() { }
@Bean
public FeignAcceptGzipEncodingInterceptor feignAcceptGzipEncodingInterceptor(FeignClientEncodingProperties properties) {
return new FeignAcceptGzipEncodingInterceptor(properties);
}
}
@ConditionalOnMissingBean注解表示不包含指定Bean时条件匹配(未启用OKHttp3时进行压缩配置)
编码器与解码器配置
Feign中提供了自定义的编码解码器设置,同时也提供了多种编码解码器实现,我们可以用不同的编码解码器来处理数据的传输。
/** * 自定义解码器 */
public class CustomizeDecoder implements Decoder {
/**
* 解码方法
* @param response
* @param type
* @return
* @throws IOException
* @throws DecodeException
* @throws FeignException
*/
@Override
public Object decode(Response response, Type type) throws IOException, DecodeException, FeignException {
return null;
}
}
/**
* 自定义编码器
*/
public class CustomizeEncoder implements Encoder {
/**
* 编码方法
* @param o
* @param type
* @param requestTemplate
* @throws EncodeException
*/
@Override
public void encode(Object o, Type type, RequestTemplate requestTemplate) throws EncodeException {
}
}
-
配置文件方式配置Feign
#修改Feign全局默认配置名称
feign.client.default-config=feign-config
#配置链接超时时间(单位毫秒)
feign.client.config.feign-config.connect-timeout=5000
#配置读取超时时间(单位毫秒)
feign.client.config.feign-config.read-timeout=5000
#配置编码器
feign.client.config.feign-config.encoder=com.springlcoud.feign.feigndemo.code.CustomizeEncoder
#配置解码器
feign.client.config.feign-config.decoder=com.springlcoud.feign.feigndemo.code.CustomizeDecoder
#配置契约
feign.client.config.feign-config.contract=com.springlcoud.feign.feigndemo.configuration.FeignContractConfiguration
#配置重试
feign.client.config.feign-config.retryer=com.springlcoud.feign.feigndemo.configuration.FeignRetryerConfiguration
-
Feign构造多参数请求
@GetMapping("/checkLoginByRequestParam")
public String checkLoginByRequestParam(@RequestParam String loginName,String loginPass){
String resultMessage="";
return resultMessage;
}
@GetMapping("/checkLoginByRequestParams")
public String checkLoginByRequestParams(@RequestParam Map<String,Object> params){
String resultMessage="";
return resultMessage;
}
@PostMapping("/checkLoginByPostParams")
public String checkLoginByPostParams(@RequestBody Entity entity){
String resultMessage="";
return resultMessage;
}