例子此次先不寫了。。。直接源碼走起。部分設計跟Ribbon同樣,這邊就不在累述,建議先看Ribbon系列。
依然從spring.factories提及。注意到這裏有這幾個類:FeignAutoConfiguration、FeignRibbonClientAutoConfiguration。spring
加載FeignContext,這裏會賦值FeignClientSpecification的集合,
後面說FeignClientSpecification類怎麼來的,其實跟Ribbon用的是同一個方法。
FeignContext的defaultConfigType是FeignClientsConfiguration.class,這個和Ribboon用法同樣,後面會加載。segmentfault
@Autowired(required = false) private List<FeignClientSpecification> configurations = new ArrayList<>(); @Bean public FeignContext feignContext() { FeignContext context = new FeignContext(); context.setConfigurations(this.configurations); return context; }
另外一個加載的是HystrixTargeter,雖然是HystrixTargeter,若是Feign.Builder不是feign.hystrix.HystrixFeign.Builder,後面調用的仍是Feign.Builder的target方法。app
@Configuration(proxyBeanMethods = false) @ConditionalOnClass(name = "feign.hystrix.HystrixFeign") protected static class HystrixFeignTargeterConfiguration { @Bean @ConditionalOnMissingBean public Targeter feignTargeter() { return new HystrixTargeter(); } }
加載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就是他了。ide
@Bean @ConditionalOnMissingBean public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory, SpringClientFactory clientFactory) { return new LoadBalancerFeignClient(new Client.Default(null, null), cachingFactory, clientFactory); }
咱們使用feign的時候,都會使用這個註解,註解裏Import了FeignClientsRegistrar這個類,FeignClientsRegistrar實現了ImportBeanDefinitionRegistrar接口,調用registerBeanDefinitions方法。這個方法作了兩件事,一件事是註冊FeignClientSpecification類,後面會注入到上面的FeignContext中,這個用法跟Ribbon - 幾種自定義負載均衡策略提的同樣。另一件事就是建立FactoryBean。ui
@Override public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { // 註冊FeignClientSpecification類 registerDefaultConfiguration(metadata, registry); // 經過註解的信息註冊FeignClientFactoryBean類, //這個是FactoryBean,因此容器fresh的時候會調用他的getObject方法 registerFeignClients(metadata, registry); }
這個方法就會掃描EnableFeignClients和FeignClient的註解,而後註冊FeignClientFactoryBean類型的bean,這個是FactoryBean,因此容器fresh的時候會調用他的getObject方法。this
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); } } }
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的形式,代碼略 }
建立一個Feign.Builder,FeignContext#getInstance,這個類繼承了NamedContextFactory,流程和ribbon的SpringClientFactory#getContext同樣。上面提到FeignContext的defaultConfigType是FeignClientsConfiguration.class,因此還會加載OptionalDecoder解碼、SpringEncoder編碼、SpringMvcContract,解析MVC註解、NEVER_RETRY重試、DefaultFeignLoggerFactory日誌、FeignClientConfigurer、Feign.builder()。url
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; }
這裏獲取Client和Targeter類,Client就是上面的LoadBalancerFeignClient,他是全部共享的。Targeter是HystrixTargeter,他是serviceId私有的。上面已經提了他最終是調用Feign.Builder#target。spa
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); } // 異常略 }
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; }
啓動的時候,爲每一個接口,生成代理對象。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 其餘略 //dispatch.get(method)獲取的是SynchronousMethodHandler return dispatch.get(method).invoke(args); }
調用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); // 其餘略 }
@Override public 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請求,怎麼處理返回結果,都略過了。。。。。