#Feign简单分析
@(Feign)[Spring][spring cloud][feign][ribbon]
第一步:把feign相关类分装成spring内部BeanDefinition
pring-cloud-netflix-core.jar EnableFeignClients.java
spring-cloud-netflix-core.jar FeignClientsRegistrar.java
spring-cloud-netflix-core.jar FeignClientFactoryBean.java
第二步:通过ioc容器初始化BeanDefinition得到feign的bean
如果项目引用了spring-cloud-netflix-core.jar DefaultFeignLoadBalancedConfiguration.java,则会加载LoadBalancerFeignClient,使用它进行请求发送;否则,以Client.java的实现类Default进行请求发送;LoadBalancerFeignClient中默认使用Ribbon请求
spring-cloud-netflix-core.jar FeignClientFactoryBean.java
@Override
public Object getObject() throws Exception {
FeignContext context = applicationContext.getBean(FeignContext.class);
Feign.Builder builder = feign(context);
if (!StringUtils.hasText(this.url)) {
String url;
if (!this.name.startsWith("http")) {
url = "http://" + this.name;
}
else {
url = this.name;
}
url += cleanPath();
return loadBalance(builder, context, new HardCodedTarget<>(this.type,
this.name, url));
}
if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {
this.url = "http://" + this.url;
}
String url = this.url + cleanPath();
return targeter.target(this, builder, context, new HardCodedTarget<>(
this.type, this.name, url));
}
protected <T> T loadBalance(Feign.Builder builder, FeignContext context,
HardCodedTarget<T> target) {
Client client = getOptional(context, Client.class);
if (client != null) {
builder.client(client);
return targeter.target(this, builder, context, target);
}
throw new IllegalStateException(
"No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-ribbon?");
}
spring-cloud-netflix-core.jar DefaultFeignLoadBalancedConfiguration.java
@Configuration
class DefaultFeignLoadBalancedConfiguration {
@Bean
@ConditionalOnMissingBean
public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
SpringClientFactory clientFactory) {
return new LoadBalancerFeignClient(new Client.Default(null, null),
cachingFactory, clientFactory);
}
}
spring-cloud-netflix-core.jar LoadBalancerFeignClient.java
@Override
public Response execute(Request request, Request.Options options) throws IOException {
try {
URI asUri = URI.create(request.url());
String clientName = asUri.getHost();
URI uriWithoutHost = cleanUrl(request.url(), clientName);
FeignLoadBalancer.RibbonRequest ribbonRequest = new FeignLoadBalancer.RibbonRequest(
this.delegate, request, uriWithoutHost);
IClientConfig requestConfig = getClientConfig(options, clientName);
return lbClient(clientName).executeWithLoadBalancer(ribbonRequest,
requestConfig).toResponse();
}
catch (ClientException e) {
IOException io = findIOException(e);
if (io != null) {
throw io;
}
throw new RuntimeException(e);
}
}
第三步:运行时通过ReflectiveFeign调用MethodHandler
feign-core.jar ReflectiveFeign.java
feign-core.jar MethodHandler.java
feign-core.jar Client.java