1.OpenFeign简介
1.相比于Netflix Feign,OpenFeign支持Spring MVC注解,整合了Ribbon(springcloud在Hoxton.M2 RELEASED版本之后舍弃Ribbon。需手动引入spring-cloud-loadbalancer)和Nacos。
2.使得开发人员调用远程接口或者服务之间相互调用就像调用本地方法一样。
2.整合OpenFeign
1.引入OpenFeign依赖
< dependencyManagement> < dependencies> < dependency> < groupId> org.springframework.cloud</ groupId> < artifactId> spring-cloud-dependencies</ artifactId> < version> ${spring-cloud.version}</ version> < type> pom</ type> < scope> import</ scope> </ dependency> </ dependencies>
</ dependencyManagement> < dependencies> < dependency> < groupId> org.springframework.cloud</ groupId> < artifactId> spring-cloud-starter-openfeign</ artifactId> </ dependency> < dependency> < groupId> org.springframework.cloud</ groupId> < artifactId> spring-cloud-starter-loadbalancer</ artifactId> </ dependency>
</ dependencies>
2.编写调用接口+@FeignClient
FeignClient常用属性:name:指定FeignClient的名称,项目若整合注册中心(nacos),name属性会作为服务的名称,用于服务发现。
url:可以手动指定@FeignClient调用的地址。
decode404:当发生http 404错误时,如果该字段位true,会调用decoder进行解码,否则抛出FeignException
configuration:Feign配置类,可以自定义Feign的Encoder、Decoder、LogLevel、Contract
fallback:定义容错的处理类,当调用远程接口失败或超时时,会调用对应接口的容错逻辑,fallback指定的类必须实现 @FeignClient标记的接口
fallbackFactory:工厂类,用于生成fallback类示例,通过这个属性我们可以实现每个接口通用的容错逻辑,减少重复的代码
path:定义当前FeignClient的统一前缀,当我们项目中配置了server.context-path,server.servlet-path时使用
@FeignClient ( name = "servie-name" )
public interface SystemFeignService { @PostMapping ( value = "/xxx/xxxx" ) void updateXxxxx ( @RequestBody Object object) ; @GetMapping ( value = "/xxx/xxxx" ) SysUser selectXxxx ( @RequestParam ( value = "str" ) String str) ; @GetMapping ( value = "/xxx/{key}" ) String getConfigKeyXxxxx ( @PathVariable ( value = "key" ) String key) ;
}
3.启动类添加@EnableFeignClients开启FeignCleint
3.OpenFeign自定义配置
1.日志配置
接口调试、查看接口响应时间等
1)全局配置,定义配置类并指定日志级别
日志级别分为4种:NONE:不记录任何日志。适用于生产(默认值)。BASIC:仅记录请求方法,URL,响应状态代码以及执行时间。适应于生产追踪问题。HEADERS:在BASIC基础上,记录请求和响应的header。FULL:记录请求和响应的header,body和元数据。注:OpenFeign的日志级别为debug,Springboot默认的级别是info级别比OpenFeign要高,所以OpenFeign日期不会输出,需要在配置文件中设置feign接口所在目录的日志级别。
logging : level : com.initial.openFeign.service : debug
@Configuration
public class FeignConfig { @Bean public Logger. Level feignLoggerLevel ( ) { return Logger. Level . FULL ; } }
日志输出:
2)局部配置-配置类
1.将OpenFeign日志配置类上的@Configuration 去除
2.@FeignClient接口添加 configuration = FeignConfig.class
public class FeignConfig { @Bean public Logger. Level feignLoggerLevel ( ) { return Logger. Level . FULL ; } }
@FeignClient ( name = "servie-name" , configuration = FeignConfig . class )
public interface SystemFeignService { @PostMapping ( value = "/xxx/xxxx" ) void updateXxxxx ( @RequestBody Object object) ; @GetMapping ( value = "/xxx/xxxx" ) SysUser selectXxxx ( @RequestParam ( value = "str" ) String str) ; @GetMapping ( value = "/xxx/{key}" ) String getConfigKeyXxxxx ( @PathVariable ( value = "key" ) String key) ;
}
日志输出:
2)局部配置-配置文件
消费端配置文件中添加
spring : cloud : openfeign : client : config : servie-name : logger-level : FULL
2.超时时间配置
通过Options可以配置连接超时时间和读取超时时间,Options的第一个参数是连接的超时时间(ms),默认值是2s,第二个参数是请求处理的超时时间(ms),默认值是5s。
1)全局配置-配置类(局部配置不进行演示了)
@Configuration
public class FeignConfig { @Bean public Logger. Level feignLoggerLevel ( ) { return Logger. Level . BASIC ; } @Bean public Request. Options feignOptions ( ) { return new Request. Options ( 5000 , 3000 ) ; }
}
@FeignClient ( name = "servie-name" )
public interface SystemFeignService { @PostMapping ( value = "/xxx/xxxx" ) void updateXxxxx ( @RequestBody Object object) ; @GetMapping ( value = "/xxx/xxxx" ) SysUser selectXxxx ( @RequestParam ( value = "str" ) String str) ; @GetMapping ( value = "/xxx/{key}" ) String getConfigKeyXxxxx ( @PathVariable ( value = "key" ) String key) ;
}
服务端接口睡眠5s钟
try { Thread . sleep ( 5000 ) ;
} catch ( InterruptedException e) { throw new RuntimeException ( e) ;
}
请求处理超时报错:
2)局部配置-配置文件
消费端配置文件中添加
spring : cloud : openfeign : client : config : servie-name : logger-level : FULLconnect-timeout : 5000 read-timeout : 3000
请求处理超时报错:
3.自定义拦截器
可以处理服务调用时token的传递等。
全局配置类
@Configuration
public class FeignTokenInterceptor implements RequestInterceptor { @Override public void apply ( RequestTemplate requestTemplate) { String feignUrl = requestTemplate. url ( ) ; if ( feignUrl. contains ( "/xxlJob/" ) ) { RequestContextHolder . setRequestAttributes ( new ServletRequestAttributes ( new MockHttpServletRequest ( ) ) ) ; } else { HttpServletRequest request = ( ( ServletRequestAttributes ) RequestContextHolder . getRequestAttributes ( ) ) . getRequest ( ) ; String token = request. getHeader ( Constants . ACCESS_TOKEN_KEY ) ; if ( StringUtils . isNotEmpty ( token) ) { requestTemplate. header ( Constants . ACCESS_TOKEN_KEY , token) ; } } requestTemplate. header ( "X-Forwarded-For" , IpUtils . getIpAddr ( WebUtils . getRequest ( ) . get ( ) ) ) ; } }