例子这次先不写了。。。间接源码走起。局部设计跟Ribbon一样,这边就不在累述,倡议先看Ribbon系列。
仍然从spring.factories说起。留神到这里有这几个类:FeignAutoConfiguration、FeignRibbonClientAutoConfiguration。
启动
FeignAutoConfiguration
加载FeignContext,这里会赋值FeignClientSpecification的汇合,
前面说FeignClientSpecification类怎么来的,其实跟Ribbon用的是同一个办法。
FeignContext的defaultConfigType是FeignClientsConfiguration.class,这个和Ribboon用法一样,前面会加载。
@Autowired(required = false)private List<FeignClientSpecification> configurations = new ArrayList<>();@Beanpublic FeignContext feignContext() { FeignContext context = new FeignContext(); context.setConfigurations(this.configurations); return context;}
另一个加载的是HystrixTargeter,尽管是HystrixTargeter,如果Feign.Builder不是feign.hystrix.HystrixFeign.Builder,前面调用的还是Feign.Builder的target办法。
@Configuration(proxyBeanMethods = false)@ConditionalOnClass(name = "feign.hystrix.HystrixFeign")protected static class HystrixFeignTargeterConfiguration { @Bean @ConditionalOnMissingBean public Targeter feignTargeter() { return new HystrixTargeter(); }}
FeignRibbonClientAutoConfiguration
加载CachingSpringLoadBalancerFactory,这个类会注入SpringClientFactory,看过了Ribbon,是不是就晓得了他要做什么。没错,他会创立一个ILoadBalancer,用于负载平衡。
@Bean@Primary@ConditionalOnMissingBean@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")public CachingSpringLoadBalancerFactory cachingLBClientFactory( SpringClientFactory factory) { return new CachingSpringLoadBalancerFactory(factory);}
FeignRibbonClientAutoConfiguration还import了DefaultFeignLoadBalancedConfiguration类,在这个类,会创立一个LoadBalancerFeignClient,前面须要的Client就是他了。
@Bean@ConditionalOnMissingBeanpublic Client feignClient(CachingSpringLoadBalancerFactory cachingFactory, SpringClientFactory clientFactory) { return new LoadBalancerFeignClient(new Client.Default(null, null), cachingFactory, clientFactory);}
@EnableFeignClients
咱们应用feign的时候,都会应用这个注解,注解里Import了FeignClientsRegistrar这个类,FeignClientsRegistrar实现了ImportBeanDefinitionRegistrar接口,调用registerBeanDefinitions办法。这个办法做了两件事,一件事是注册FeignClientSpecification类,前面会注入到下面的FeignContext中,这个用法跟Ribbon - 几种自定义负载平衡策略提的一样。另外一件事就是创立FactoryBean。
@Overridepublic void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { // 注册FeignClientSpecification类 registerDefaultConfiguration(metadata, registry); // 通过注解的信息注册FeignClientFactoryBean类, //这个是FactoryBean,所以容器fresh的时候会调用他的getObject办法 registerFeignClients(metadata, registry);}
这个办法就会扫描EnableFeignClients和FeignClient的注解,而后注册FeignClientFactoryBean类型的bean,这个是FactoryBean,所以容器fresh的时候会调用他的getObject办法。
public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { LinkedHashSet<BeanDefinition> candidateComponents = new LinkedHashSet<>(); // 扫描EnableFeignClients注解 Map<String, Object> attrs = metadata .getAnnotationAttributes(EnableFeignClients.class.getName()); AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter( FeignClient.class); final Class<?>[] clients = attrs == null ? null : (Class<?>[]) attrs.get("clients"); // 如果EnableFeignClients没有配置clients信息,扫描FeignClient注解 if (clients == null || clients.length == 0) { ClassPathScanningCandidateComponentProvider scanner = getScanner(); scanner.setResourceLoader(this.resourceLoader); // 扫描FeignClient注解 scanner.addIncludeFilter(new AnnotationTypeFilter(FeignClient.class)); Set<String> basePackages = getBasePackages(metadata); for (String basePackage : basePackages) { candidateComponents.addAll(scanner.findCandidateComponents(basePackage)); } } else { // 如果配置clients信息,就疏忽FeignClient注解,间接读取clients信息 for (Class<?> clazz : clients) { candidateComponents.add(new AnnotatedGenericBeanDefinition(clazz)); } } 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); registerClientConfiguration(registry, name, attributes.get("configuration")); // 注册FeignClientFactoryBean registerFeignClient(registry, annotationMetadata, attributes); } }}
FeignClientFactoryBean#getObject
getObject会调用getTarget办法,他会创立一个Feign.Builder,创立的时候会传FeignContext,这个FeignContext的加载在下面曾经提过了。而后调用loadBalance办法返回代理对象,这个代理就是前面近程调用用的。
<T> T getTarget() { FeignContext context = applicationContext.getBean(FeignContext.class); Feign.Builder builder = feign(context); if (!StringUtils.hasText(url)) { if (!name.startsWith("http")) { url = "http://" + name; } else { url = name; } url += cleanPath(); return (T) loadBalance(builder, context, new HardCodedTarget<>(type, name, url)); } // 间接ip的模式,代码略}
FeignClientFactoryBean#feign
创立一个Feign.Builder,FeignContext#getInstance,这个类继承了NamedContextFactory,流程和ribbon的SpringClientFactory#getContext一样。下面提到FeignContext的defaultConfigType是FeignClientsConfiguration.class,所以还会加载OptionalDecoder解码、SpringEncoder编码、SpringMvcContract,解析MVC注解、NEVER_RETRY重试、DefaultFeignLoggerFactory日志、FeignClientConfigurer、Feign.builder()。
protected Feign.Builder feign(FeignContext context) { FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class); Logger logger = loggerFactory.create(type); // @formatter:off Feign.Builder builder = get(context, Feign.Builder.class) // required values .logger(logger) .encoder(get(context, Encoder.class)) .decoder(get(context, Decoder.class)) .contract(get(context, Contract.class)); // @formatter:on // 整合配置Feign.Builder configureFeign(context, builder); return builder;}
FeignClientFactoryBean#loadBalance
这里获取Client和Targeter类,Client就是下面的LoadBalancerFeignClient,他是所有共享的。Targeter是HystrixTargeter,他是serviceId公有的。下面曾经提了他最终是调用Feign.Builder#target。
protected <T> T loadBalance(Feign.Builder builder, FeignContext context, HardCodedTarget<T> target) { Client client = getOptional(context, Client.class); if (client != null) { builder.client(client); Targeter targeter = get(context, Targeter.class); return targeter.target(this, builder, context, target); } // 异样略}
Feign.Builder#target
build办法是构建一个ReflectiveFeign对象,newInstance是生成代理对象。
public <T> T target(Target<T> target) { return build().newInstance(target);}
build办法中,ReflectiveFeign创立的时候传了ParseHandlersByName,InvocationHandlerFactory,SynchronousMethodHandler三个对象。
public Feign build() { // 其余略 return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);}
代理对象生成,生成后,前面对代理对象的拜访,都会调用FeignInvocationHandler#invoke办法。
public <T> T newInstance(Target<T> target) { // ParseHandlersByName是通过Contrac用来解析接口定义。 Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target); // 给每个办法创立一个SynchronousMethodHandler对象 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))); } } // 创立一个InvocationHandler对象,这里是FeignInvocationHandler InvocationHandler handler = factory.create(target, methodToHandler); T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(), new Class<?>[] {target.type()}, handler); for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) { defaultMethodHandler.bindTo(proxy); } return proxy;}
总结
启动的时候,为每个接口,生成代理对象。
办法调用
FeignInvocationHandler#invoke
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 其余略 //dispatch.get(method)获取的是SynchronousMethodHandler return dispatch.get(method).invoke(args);}
SynchronousMethodHandler#invoke
调用LoadBalancerFeignClient#execute,LoadBalancerFeignClient加载下面曾经讲过了。
public Object invoke(Object[] argv) throws Throwable { RequestTemplate template = buildTemplateFromArgs.create(argv); // 其余略 return executeAndDecode(template, options); // 其余略}Object executeAndDecode(RequestTemplate template, Options options) throws Throwable { // 其余略 response = client.execute(request, options); // 其余略}
LoadBalancerFeignClient#execute
@Overridepublic Response execute(Request request, Request.Options options) throws IOException { try { // 获取Uri URI asUri = URI.create(request.url()); // 获取serviceId 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); // 获取FeignLoadBalancer,通过FeignLoadBalancer调用申请 return lbClient(clientName) .executeWithLoadBalancer(ribbonRequest, requestConfig).toResponse(); } catch (ClientException e) { IOException io = findIOException(e); if (io != null) { throw io; } throw new RuntimeException(e); }}
lbClientFactory是CachingSpringLoadBalancerFactory,所以调用CachingSpringLoadBalancerFactory#create的create办法。
CachingSpringLoadBalancerFactory有个相熟的SpringClientFactory对象,他负责获取ILoadBalancer、IClientConfig、ServerIntrospector,而后通过这三个构建一个FeignLoadBalancer对象。既然失去了ILoadBalancer,那后续负载平衡的局部就不再持续了,参考Ribbon - 负载平衡流程。
private FeignLoadBalancer lbClient(String clientName) { return this.lbClientFactory.create(clientName);}public FeignLoadBalancer create(String clientName) { FeignLoadBalancer client = this.cache.get(clientName); if (client != null) { return client; } IClientConfig config = this.factory.getClientConfig(clientName); ILoadBalancer lb = this.factory.getLoadBalancer(clientName); ServerIntrospector serverIntrospector = this.factory.getInstance(clientName, ServerIntrospector.class); client = this.loadBalancedRetryFactory != null ? new RetryableFeignLoadBalancer(lb, config, serverIntrospector, this.loadBalancedRetryFactory) : new FeignLoadBalancer(lb, config, serverIntrospector); this.cache.put(clientName, client); return client;}
总结
次要是通过代理对象,而后调用Ribbon进行负载平衡。咱们这边只讲述了主流程,怎么构建HTTP申请,怎么解决返回后果,都略过了。。。。。