1.加载并解析@FeignClient注解标记的接口:
在启动类上加@EnableFeignClients,import FeignClientsRegistrar.class;
由于 FeignClientsRegistrar implement ImportBeanDefinitionRegistrar,所以会执行registerBeanDefinitions方法。registerBeanDefinitions方法包含两个方法:
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
//将标注@EnableFeignClients的类:com.xxx.Application.java 以
//default.com.xxx.Application.FeignClientSpecification 为beanName注入到
//spring容器中。
//最终,feign相关的对象都以FeignClientSpecification class对象 注入到spring容器中。
registerDefaultConfiguration(metadata, registry);
// 重要
registerFeignClients(metadata, registry);
}
registerFeignClients方法主要包含两个方法:
//遍历@EnableFeignClients指定包下面@FeignClient指定的接口,
//为每个feign 生成 FeignClientSpecification 的beanDefinition,
//然后注入spring容器
registerClientConfiguration(registry, name, className,
attributes.get("configuration"));
// 解析@FeignClient注解的参数,构建FeignClientFactoryBean
registerFeignClient(registry, annotationMetadata, attributes);
构建FeignClientFactoryBean的过程:
放入beanDefinitonMap后:
加载解析@FeignClient结束。
总结:@EnableFeignClients 主要做了两件事
1.将主类和@FeignClient标记的接口转换成FeignClientSpecification对象;
2.解析@FeignClient注解的参数,构建FeignClientFactoryBean对象
2.FeignClientSpecification放入FeignContext中,后续对feign的操作都需要从FeignContext中获取。
(这一步操作和Ribbon一样,Ribbon是将RibbonClientSpecification放入SpringClientFactroy,SpringClientFactory和FeignContext都继承了NamedContextFactory,实现容器隔离,每个ribbon或者feign都有一个独立的容器,互不影响)
openfeign-core 包通过SpringBoot的自动装配加载 FeignAutoConfiguration对象
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Feign.class)
@EnableConfigurationProperties({ FeignClientProperties.class, FeignHttpClientProperties.class,
FeignEncoderProperties.class })
public class FeignAutoConfiguration {
private static final Log LOG = LogFactory.getLog(FeignAutoConfiguration.class);
//引入所有feign对象-FeignClientSpecification
@Autowired(required = false)
private List<FeignClientSpecification> configurations = new ArrayList<>();
public FeignContext feignContext() {
FeignContext context = new FeignContext();
//将feign对象放入context中,供FeignClientFactoryBean生成feign的代理对象
context.setConfigurations(this.configurations);
return context;
}
。。。。。。。。。。。。。。。。。。。。。
。。。。。。。。。。。。。。。。。。。。。
}
这一阶段结束。
总结:将每一个feign对象放入一个独立的FeignContext容器中,供后续操作。
3.FeignClientFactoryBean生成feign代理对象的过程
在业务类中通过@Autowired引入feign定义的接口时,就会创建feign对象,由于beanDefinitionMap中已经存在以接口全路径为key,FeignClientFactoryBean为value的键值对,所以会去创建FeignClientFactoryBean对象。
FeignClientFactoryBean 实现了 FactoryBean 和 InitializingBean:
实现了FactoryBean,通过调用getObject()方法,创建bean对象(懒加载)。
实现了InitializingBean,在Bean初始化时,会调用afterPropertiesSet()方法(在该方法中调用getObject方法,实现提前加载)。
getObject 过程
调用getTarget方法:
在有负载均衡时,调用loadBalance方法:
protected <T> T loadBalance(Feign.Builder builder, FeignClientFactory context, HardCodedTarget<T> target) {
//获取所有 implement Client 接口的 http工具类
//(拦截feign打印日志 可以通过 implement Client 来实现)
Client client = getOptional(context, Client.class);
if (client != null) {
//给feign设置 http工具类
builder.client(client);
//使用默认的Targeter还是HystrixTargeter是通过
//FeignAutoConfiguration配置的
Targeter targeter = get(context, Targeter.class);
//创建feign代理对象
return targeter.target(this, builder, context, target);
}
==============================================================
//获取一个LoadBalancerFeignClient对象(拦截feign日志,自定义Client时,
//需要最终组装LoadBalancerFeignClient对象,才能拦截到)
protected <T> T getOptional(FeignClientFactory context, Class<T> type) {
return context.getInstance(contextId, type);
}
==============================================================
LoadBalancerFeignClient implement Client,调用execute方法,
会去调用delegate(也是个Client,自定义Client时,将已经有的Client
通过delegate赋值给自定义的Client,就能调用自定义的Client了)
targeter.target(this, builder, context, target); 创建feign代理对象targeter看HystrixTargeter对象:
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
FeignContext context, Target.HardCodedTarget<T> target) {
//非HystrixFeign
if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) {
return feign.target(target);
}
feign.hystrix.HystrixFeign.Builder builder = (feign.hystrix.HystrixFeign.Builder) feign;
String name = StringUtils.isEmpty(factory.getContextId()) ? factory.getName()
: factory.getContextId();
SetterFactory setterFactory = getOptional(name, context, SetterFactory.class);
if (setterFactory != null) {
builder.setterFactory(setterFactory);
}
//设置fallback
Class<?> fallback = factory.getFallback();
if (fallback != void.class) {
return targetWithFallback(name, context, target, builder, fallback);
}
//设置fallbackFactory
Class<?> fallbackFactory = factory.getFallbackFactory();
if (fallbackFactory != void.class) {
return targetWithFallbackFactory(name, context, target, builder,
fallbackFactory);
}
//会调用Feign的target方法
return feign.target(target);
}
feign的target方法:
public <T> T target(Target<T> target) {
return build().newInstance(target);
}
=========================================
//构建feign
public Feign build() {
Client client = Capability.enrich(this.client, capabilities);
Retryer retryer = Capability.enrich(this.retryer, capabilities);
List<RequestInterceptor> requestInterceptors = this.requestInterceptors.stream()
.map(ri -> Capability.enrich(ri, capabilities))
.collect(Collectors.toList());
Logger logger = Capability.enrich(this.logger, capabilities);
Contract contract = Capability.enrich(this.contract, capabilities);
Options options = Capability.enrich(this.options, capabilities);
Encoder encoder = Capability.enrich(this.encoder, capabilities);
Decoder decoder = Capability.enrich(this.decoder, capabilities);
InvocationHandlerFactory invocationHandlerFactory =
Capability.enrich(this.invocationHandlerFactory, capabilities);
QueryMapEncoder queryMapEncoder = Capability.enrich(this.queryMapEncoder, capabilities);
SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
logLevel, decode404, closeAfterDecode, propagationPolicy, forceDecoding);
ParseHandlersByName handlersByName =
new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,
errorDecoder, synchronousMethodHandlerFactory);
//返回一个ReflectiveFeign feign对象
return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
}
}
==============================================
public <T> T newInstance(Target<T> target) {
Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();
List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>();
for (Method method : target.type().getMethods()) {
if (method.getDeclaringClass() == Object.class) {
continue;
} else if (Util.isDefault(method)) {
DefaultMethodHandler handler = new DefaultMethodHandler(method);
defaultMethodHandlers.add(handler);
methodToHandler.put(method, handler);
} else {
methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
}
}
//生成 HystrixInvocationHandler对象
//(InvocationHandler接口是proxy代理实例真实调用处理程序需要实现的一个接口,
//每一个proxy代理实例都要有一个关联的InvocationHandler;在代理实例调用方法时,
//方法调用被分派去调用InvocationHandler的invoke方法。)
InvocationHandler handler = factory.create(target, methodToHandler);
//通过jdk代理生成代理对象。
//new Class<?>[] {target.type()}:一个interface数组,
//声明了代理类实现了哪些接口,可以调用哪些方法(接口定义的所有方法)
T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
new Class<?>[] {target.type()}, handler);
for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
defaultMethodHandler.bindTo(proxy);
}
return proxy;
}
这一段结束。
总结:通过@Autowired引入feign接口时,调用FeignClientFactoryBean getObject方法生成对应的代理类。
4.feign调用过程
当调用一个feign方法时,会调用HystrixInvocationHandler 类的invoke方法
public Object invoke(final Object proxy, final Method method, final Object[] args)
throws Throwable {
。。。。。。。。。。。。。。
。。。。。。。。。。。。。。
HystrixCommand<Object> hystrixCommand =
new HystrixCommand<Object>(setterMethodMap.get(method)) {
@Override
protected Object run() throws Exception {
try {
//从dispatch中获取具体调用方法,然后调用SynchronousMethodHandler的invoke方法
return HystrixInvocationHandler.this.dispatch.get(method).invoke(args);
} catch (Exception e) {
throw e;
} catch (Throwable t) {
throw (Error) t;
}
}
..................
..................
return hystrixCommand.execute();
}
SynchronousMethodHandler类的invoke方法:
public Object invoke(Object[] argv) throws Throwable {
//创建RequestTemplate
RequestTemplate template = buildTemplateFromArgs.create(argv);
Options options = findOptions(argv);
Retryer retryer = this.retryer.clone();
while (true) {
try {
//主要方法
return executeAndDecode(template, options);
} catch (RetryableException e) {
try {
retryer.continueOrPropagate(e);
} catch (RetryableException th) {
Throwable cause = th.getCause();
if (propagationPolicy == UNWRAP && cause != null) {
throw cause;
} else {
throw th;
}
}
if (logLevel != Logger.Level.NONE) {
logger.logRetry(metadata.configKey(), logLevel);
}
continue;
}
}
}
=====================================================
Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {
//RequestTemplate转Request
Request request = targetRequest(template);
if (logLevel != Logger.Level.NONE) {
logger.logRequest(metadata.configKey(), logLevel, request);
}
Response response;
long start = System.nanoTime();
try {
//执行clent-->LoadBalancerFeignClient 的execute方法
response = client.execute(request, options);
// ensure the request is set. TODO: remove in Feign 12
response = response.toBuilder()
.request(request)
.requestTemplate(template)
.build();
} catch (IOException e) {
if (logLevel != Logger.Level.NONE) {
logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime(start));
}
throw errorExecuting(request, e);
}
long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
//解码
if (decoder != null)
return decoder.decode(response, metadata.returnType());
CompletableFuture<Object> resultFuture = new CompletableFuture<>();
asyncResponseHandler.handleResponse(resultFuture, metadata.configKey(), response,
metadata.returnType(),
elapsedTime);
try {
if (!resultFuture.isDone())
throw new IllegalStateException("Response handling not done");
return resultFuture.join();
} catch (CompletionException e) {
Throwable cause = e.getCause();
if (cause != null)
throw cause;
throw e;
}
}
LoadBalancerFeignClient 的execute方法:
方法1 :
factory--SpringClientFactory,是装载Ribbon BeanDefinition的容器,并加载RibbonClientConfiguration配置类。
最终会调用getBean,会调用:
方法 2 是获取具体server的地方:
调用ZoneAwareLoadBalancer的chooseServer方法,然后调用父类的chooseServer方法:
feign调用介绍到这里,Ribbon相关操作请查看Ribbon调用