目录
本文主要包含 feign-client的注册,feignClient调用的序列化,反序列化,ribon的重试
注入的过程类似spring-mybatis,不过一个是通过spring.factories文件内写配置文件,一个是通过ImportBeanDefinitionRegistrar,整体的代理过程也是非常类似,都是将参数封装成模板,交给执行器(client,sqlSession)去execute
注入feign
- 使用EnableFeignClients配置扫描路径或者类
- 遍历所有的路径或类,生成相应的beanDefinition(做一些校验,排除非接口类等)
- 获取bean name,配置编码解吗,注入feignClientFactory
重要的class
class/annotation | 参数 | 功能简介 |
---|---|---|
@EnableFeignClients | 扫描包,将@FeignClient注解的接口托管给spring | |
FeignClientsRegistrar | 实现了ImportBeanDefinitionRegistrar,ResourceLoaderAware,EnvironmentAware。很明显,是托管扫描的@FeignClient,托管给Spring |
FeignClientsRegistrar
1 | public void registerFeignClients(AnnotationMetadata metadata, |
FeignClientFactoryBean
1 | class FeignClientFactoryBean |
注入client
以ApacheHttpClient,BlockingLoadBalancerClient为例,装配及注入在HttpClientFeignLoadBalancerConfiguration类中
HttpClientFeignLoadBalancerConfiguration
1 |
|
feign代理类的实现
ReflectiveFeign
1 |
|
解析参数
通过内部类ParseHandlersByName,
1 | static final class ParseHandlersByName{ |
序列化与反序列化
SynchronousMethodHandler
这个类就是真正feignClient中的接口调用的invoke方法了。
1 |
|
负载均衡
ribbon的实现为LoadBalancerFeignClient,略微复杂一点,和ribbon结合不够完美。用了装饰者模式进行二次封装
本文就以spring-cloud-loadBalancer实现看源码
FeignBlockingLoadBalancerClient
主要通过负载均衡获取服务的注册信息,根据负载均衡策略获取ServiceInstance,构建出真实的URL,然后封装成统一的Request交给delegate去执行请求。最后将响应的Response交给SynchronousMethodHandler#executeAndDecode方法
1 | public class FeignBlockingLoadBalancerClient implements Client { |
feign与hystrix
在FeignClientsConfiguration
类中可以找到如下代码,即有hystrixCommand,hystrixFeign
类的时候创建hystrixFeignClientBuidler
.
1 |
|
在FeignAutoConfiguration
类中
1 |
|
hystrix-target
1 | // 核心也就是这段代码了 |
hystrix-feign
1 |
|
HystrixInvocationHandler
```java
@Override
public Object invoke(final Object proxy, final Method method, final Object[] args)
throws Throwable {
// early exit if the invoked method is from java.lang.Object
// code is the same as ReflectiveFeign.FeignInvocationHandler
if (“equals”.equals(method.getName())) {
try {
Object otherHandler =
args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;
return equals(otherHandler);
} catch (IllegalArgumentException e) {
return false;
}
} else if (“hashCode”.equals(method.getName())) {
return hashCode();
} else if (“toString”.equals(method.getName())) {
return toString();
}
HystrixCommand<Object> hystrixCommand =
new HystrixCommand<Object>(setterMethodMap.get(method)) {
@Override
protected Object run() throws Exception {
try {
return HystrixInvocationHandler.this.dispatch.get(method).invoke(args);
} catch (Exception e) {
throw e;
} catch (Throwable t) {
throw (Error) t;
}
}
@Override
protected Object getFallback() {
if (fallbackFactory == null) {
return super.getFallback();
}
try {
Object fallback = fallbackFactory.create(getExecutionException());
Object result = fallbackMethodMap.get(method).invoke(fallback, args);
if (isReturnsHystrixCommand(method)) {
return ((HystrixCommand) result).execute();
} else if (isReturnsObservable(method)) {
// Create a cold Observable
return ((Observable) result).toBlocking().first();
} else if (isReturnsSingle(method)) {
// Create a cold Observable as a Single
return ((Single) result).toObservable().toBlocking().first();
} else if (isReturnsCompletable(method)) {
((Completable) result).await();
return null;
} else if (isReturnsCompletableFuture(method)) {
return ((Future) result).get();
} else {
return result;
}
} catch (IllegalAccessException e) {
// shouldn't happen as method is public due to being an interface
throw new AssertionError(e);
} catch (InvocationTargetException | ExecutionException e) {
// Exceptions on fallback are tossed by Hystrix
throw new AssertionError(e.getCause());
} catch (InterruptedException e) {
// Exceptions on fallback are tossed by Hystrix
Thread.currentThread().interrupt();
throw new AssertionError(e.getCause());
}
}
};
if (Util.isDefault(method)) {
return hystrixCommand.execute();
} else if (isReturnsHystrixCommand(method)) {
return hystrixCommand;
} else if (isReturnsObservable(method)) {
// Create a cold Observable
return hystrixCommand.toObservable();
} else if (isReturnsSingle(method)) {
// Create a cold Observable as a Single
return hystrixCommand.toObservable().toSingle();
} else if (isReturnsCompletable(method)) {
return hystrixCommand.toObservable().toCompletable();
} else if (isReturnsCompletableFuture(method)) {
return new ObservableCompletableFuture<>(hystrixCommand);
}
return hystrixCommand.execute();
}
```