Feign让客户端调用变得非常简单
使用
添加maven依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
增加注解@EnableFeignClients
注意 @EnableFeignClients注解的clients和basePackages同时配置的话只有clients生效
这个看一下FeignClientsRegistrar.registerFeignClients源码就可以很好理解了
@EnableFeignClients(clients = {com.**.IUserFeign.class})
客户端@FeignClient
- 参数value, 如果调用微服务环境中的应用,value等于服务的名字,也可以是一个完整的http接口请求前缀
- 参数path, 其实默认为/,可以不用配置,如果请求方法有公共前缀或者服务有站点路径可以配置在这里。
@FeignClient(value = "sso", path="/")
public interface IUserFeign{
@RequestMapping(value = "/user/{id}", method = RequestMethod.GET)
public User getUserById(@PathVariable String id)
}
配置一个FeignConfiguration
RequestMappingHandlerMapping的部分源码如下,可以看出只要有Controller注解或者有RequestMapping注解就会进行请求注册,我们调用外部接口的时候是不需要将@FeignClient接口类中@RequestMapping注解的方法注册到mvc中,所以需要修改注册规则
protected boolean isHandler(Class<?> beanType) {
return AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) || AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class);
}
import feign.Feign;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
@Configuration
@ConditionalOnClass({Feign.class})
public class FeignConfiguration {
@Bean
public WebMvcRegistrations feignWebRegistrations() {
return new WebMvcRegistrations() {
@Override
public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
return new FeignRequestMappingHandlerMapping();
}
};
}
private static class FeignRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
@Override
protected boolean isHandler(Class<?> beanType) {
return super.isHandler(beanType) &&
!AnnotatedElementUtils.hasAnnotation(beanType, FeignClient.class);
}
}
}
Feign默认是会重试的, new Retryer.Default()源码可以看出最多重试5次
有一个业务是失败一次就直接提示用户稍后再试,增加下面注解来禁止重试
@Bean
Retryer feignRetryer() {
return new Retryer() {
@Override
public void continueOrPropagate(RetryableException e) {
throw e;
}
@Override
public Retryer clone() {
return this;
}
};
}
超时时间设置
默认1秒就超时,也太短了
feign:
client:
config:
default:
connect-timeout: 10000
read-timeout: 120000
hystrix:
enabled: true
compression:
request:
enabled: true
mime-types: text/xml,application/xml,application/json
min-request-size: 2048
max-request-size: 2097152000
要点和问题
1.Error creating bean with name ‘mvcResourceUrlProvider’: Requested bean is currently in creation: Is there an unresolvable circular reference?
出现错误现象如下, 有些原因不明,如果有大神看到请帮忙解释一下:
- dev,test,uat,本地电脑打的jar包都能正常运行,线上发布打的jar包就是会报上面的错误,后面发现线上打的jar包还有20%的概率也能正常运行(求解释)
- 正常运行的jar包和运行异常的jar包我用beyond compare都比较过,内容完全一样
- 正常的jar包每次启动都运行正常,启动报错的jar包每次都会报错,启动报错的包拷贝到本地指定dev,test,uat环节启动都会报错,(有一段时间发布我们线上发布都是从uat拷贝jar包)
- 有很多微服务中都在拦截器中有使用feign接口,但是只有一个服务线上打包才报错(求解释)
参考大神的一篇文章 springcloud 拦截器注入Feign接口导致循环依赖问题解决
直接列出结论:
如果在拦截器中有地方用到了feign接口就会出现循环依赖的错误,这个时候在feign注入的地方加上@Lazy注解问题就能解决
@Configuration
public class WebMvcConfigurer extends WebMvcConfigurationSupport {
@Lazy
@Override
private IUserFeign userFeign;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new HandlerInterceptorAdapter() {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
}
}).addPathPatterns("/**");
}
2.Hystrix circuit short-circuited and is OPEN
服务提供方会报错,服务提供方参照下面的文章增加配置
Hystrix circuit short-circuited and is OPEN 异常
hystrix.command.default.circuitBreaker.requestVolumeThreshold=1000
hystrix.threadpool.default.coreSize=100
#断路器超时设置和请求的超时
hystrix.command.default.execution.timeout.enabled=true
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=300000
ribbon.ConnectTimeout=300000
ribbon.ReadTimeout=300000
#设置回退的最大线程数
hystrix.command.default.fallback.isolation.semaphore.maxConcurrentRequests=50