引入了Feign,也就是引入了Ribbon,可以自己看Feign的starter
一般来说,我们想要feign进行远程调用,只需要如下配置就行,加上@EnableFeignClients
暴露出来的Feign接口一般是这样的
其他服务想要调用它,把它引入进来,然后调用就行
一、自动配置
二、FeignClientRegistrar详解
- registerDefaultConfiguration 看@EnableFeiginClients上有没有配置默认配置类,如果有的话,就注册到容器中
- registerFeignClients 这个类更重要,这个类扫描@FeignClients的接口,并且创建代理对象
public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
ClassPathScanningCandidateComponentProvider scanner = getScanner();
scanner.setResourceLoader(this.resourceLoader);
Set<String> basePackages;
// 获取扫描路径
// 扫描所有路径,默认情况下扫描启动类下的路径
for (String basePackage : basePackages) {
Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents(basePackage);
// 遍历扫描到的FeignClient的Bean
for (BeanDefinition candidateComponent : candidateComponents) {
if (candidateComponent instanceof AnnotatedBeanDefinition) {
// verify annotated class is an interface
AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
Assert.isTrue(annotationMetadata.isInterface(), "@FeignClient can only be specified on an interface");
Map<String, Object> attributes = annotationMetadata.getAnnotationAttributes(FeignClient.class.getCanonicalName());
String name = getClientName(attributes);
// 注册FeignClient的配置
registerClientConfiguration(registry, name, attributes.get("configuration"));
// 注册FeignClient
registerFeignClient(registry, annotationMetadata, attributes);
}
}
}
}
private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
String className = annotationMetadata.getClassName();
// 生成FeignClientFactoryBean这个BeanDefinition构造器
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class);
// 将@FeignClient的注解属性添加到builder
definition.addPropertyValue("url", getUrl(attributes));
definition.addPropertyValue("path", getPath(attributes));
String name = getName(attributes);
definition.addPropertyValue("name", name);
String contextId = getContextId(attributes);
definition.addPropertyValue("contextId", contextId);
definition.addPropertyValue("type", className);
definition.addPropertyValue("decode404", attributes.get("decode404"));
definition.addPropertyValue("fallback", attributes.get("fallback"));
definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
String alias = contextId + "FeignClient";
AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
// ...
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, new String[] { alias });
// 注册
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
}
将扫描到的FeignClient接口类最终注册到了Spring容器中,这里我们注意到在设置BeanClass的时候设置的是FeignClientFactoryBean.class, 也就是说往Spring容器中注入的是一个FactoryBean对象,熟悉Spring源码的就知道这是个工厂bean,它是为了创建bean对象,最终会走到它的getObject方法。
给你们看一下spring实例化的调用栈:
三、FeignClientFactoryBean详解
其实我们基本上也能猜到,它在做什么? 基本上就是在调用getObject的时候,创建FeignClient代理对象
简单的说一下流程:
- 构建了一个FeignContext上下文,可以理解为一个FeignClient有一个上下文
- 构建Feign.Builder对象,实际上创建的是HystrixFeign.Builder,后面要设置很多内容,才能把Feign创建出来
- 调用loadBalance的时候,设置上了client, !!!记住,这个client是LoadBalanceFeignClient,后面有用
- targeter.target(this, builder, context, target),开始准备创建代理对象了
- 调用到targetWithFallback,接下来又调用到HystrixFeign.builder.target的方法,这个方法拿fallback开始创建Feign,实际上我们得到是ReflectiveFeign
- 接下来调用ReflectiveFeign.instance, 这里比较重要
a. 将方法和SynchronousMethodHandler 放到methodToHander中
b. 创建InvocationHandler, 创建JDK动态代理,这一步是缺少不了的,一般InvocationHander都会持有很多东西,在代理的时候,要做事情嘛,向这里就是持有了methodToHander
c. 通过JDK创建动态代理对象
四、InvocationHandler如何接受请求
这个client就是刚开始构建HystrixFeignBuilder的时候,设置的LoadBalanceFeignClient
lbClient(clientName)看看到底是什么负载均衡器,尝试看看
关注一下它的类继承体系:
lbClient(clientName).executeWithLoadBalancer 又是如何如何实现负载均衡拿?
public T executeWithLoadBalancer(final S request, final IClientConfig requestConfig) throws ClientException {
LoadBalancerCommand<T> command = buildLoadBalancerCommand(request, requestConfig);
try {
return command.submit(
new ServerOperation<T>() {
@Override
public Observable<T> call(Server server) {
// 回调返回选择好的Server对象,并重新构造uri地址
URI finalUri = reconstructURIWithServer(server, request.getUri());
S requestForServer = (S) request.replaceUri(finalUri);
try {
// 执行ribbon的request请求
return Observable.just(AbstractLoadBalancerAwareClient.this.execute(requestForServer, requestConfig));
}
catch (Exception e) {
return Observable.error(e);
}
}
})
.toBlocking()
.single();
} catch (Exception e) {
//
}
}
如果不关心负载均衡的情况,这里其实就是直接执行ribbon的request请求了。也就是IClient这个接口类定义的内容。不过FeignLoadBalancer需要进行一次负载选择Server,然后才回调这里的call来发起请求。
跟进submit方法看看,submit方法先是进行了一次选择获得了一个Server对象,然后回调了上面说的ribbon的request执行
public Observable<T> submit(final ServerOperation<T> operation) {
// ...
// Use the load balancer
Observable<T> o =
// 选择Server
(server == null ? selectServer() : Observable.just(server))
.concatMap(new Func1<Server, Observable<T>>() {
@Override
// Called for each server being selected
public Observable<T> call(Server server) {
context.setServer(server);
//
// Called for each attempt and retry
Observable<T> o = Observable
.just(server)
.concatMap(new Func1<Server, Observable<T>>() {
@Override
public Observable<T> call(final Server server) {
// ...
// 回调ribbon的request请求
return operation.call(server).doOnEach(
// ...
);
}
});
if (maxRetrysSame > 0)
o = o.retry(retryPolicy(maxRetrysSame, true));
return o;
}
});
// ...
}
继续跟进selectServer,看看是如何选择服务的?
private Observable<Server> selectServer() {
return Observable.create(new OnSubscribe<Server>() {
@Override
public void call(Subscriber<? super Server> next) {
try {
// 从上下文中获取
Server server = loadBalancerContext.getServerFromLoadBalancer(loadBalancerURI, loadBalancerKey);
next.onNext(server);
next.onCompleted();
} catch (Exception e) {
next.onError(e);
}
}
});
}
这里会创建loadBalancer,debug源代码这里显示的是ZoneAwareLoadBalancer,接下来就是调用chonseServer
通过不同的负载均衡规则来找一台server,最后拿到server之后 回调之前这部分代码