SpringCloud Feign源码解析
结论
@EnableFeignClients注解将类FeignClientsRegistrar注册到Spring中
FeignClientsRegistrar类主要是扫描包路径下的所有类,将带有@FeignClient注解的类或接口注册到Spring中
如何注册带有@FeignClient的类或接口呢?就是生成一个BeanDefinitionHolder类,beanName为@FeignClient所在接口的名称,beanDefinition为FeignClientFactoryBean,并将@FeignClient的属性添加到FeignClientFactoryBean中
至此,我们已经把带有@FeignClient注解的类或接口注册到Spring中
FeignClientFactoryBean.getObject()方法返回的是一个代理类,InvocationHandler中包含类中每个方法对应的MethodHandler,也就是SynchronousMethodHandler,方法真正执行就是SynchronousMethodHandler.invoke()方法
LoadBalancerFeignClient.execute()方法进行业务的处理,在这一步操作中就用到了ribbon和Hystrix功能
1. 分析注解@EnableFeignClients
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Import(FeignClientsRegistrar.class)// 重点在这里,注入FeignClientsRegistrar类 public @interface EnableFeignClients { }
2. FeignClientsRegistrar.java分析
通过其类结构可知,其实现了ImportBeanDefinitionRegistrar接口,那么在registerBeanDefinitions()中就会注册一些bean到Spring中
class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware{ @Override public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { // 1.针对那些在@EnableFeignClients中添加了defaultConfiguration属性的进行操作 // 将这些类定义的bean添加到容器中 registerDefaultConfiguration(metadata, registry); // 2.注册那些添加了@FeignClient的类或接口 // 重点就在这里 registerFeignClients(metadata, registry); } }
3. registerFeignClients(metadata, registry)方法分析
public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { ClassPathScanningCandidateComponentProvider scanner = getScanner(); scanner.setResourceLoader(this.resourceLoader); // 1.以下代码的主要功能是扫描包下的所有带有@FeignClient注解的类 Set<String> basePackages; Map<String, Object> attrs = metadata .getAnnotationAttributes(EnableFeignClients.class.getName()); // @FeignClient注解过滤器 AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter( FeignClient.class); final Class<?>[] clients = attrs == null ? null : (Class<?>[]) attrs.get("clients"); if (clients == null || clients.length == 0) { // 在这里获取带有@FeignClient注解的类,放在basePackages中 scanner.addIncludeFilter(annotationTypeFilter); basePackages = getBasePackages(metadata); } else { final Set<String> clientClasses = new HashSet<>(); basePackages = new HashSet<>(); for (Class<?> clazz : clients) { basePackages.add(ClassUtils.getPackageName(clazz)); clientClasses.add(clazz.getCanonicalName()); } AbstractClassTestingTypeFilter filter = new AbstractClassTestingTypeFilter() { @Override protected boolean match(ClassMetadata metadata) { String cleaned = metadata.getClassName().replaceAll("\\$", "."); return clientClasses.contains(cleaned); } }; scanner.addIncludeFilter( new AllTypeFilter(Arrays.asList(filter, annotationTypeFilter))); } // 2.针对所有带有@FeignClient注解的类或接口分别封装 // 注册其Configuration类(如果有的话) // 并将类或接口本身注入到Spring中 for (String basePackage : basePackages) { Set<BeanDefinition> candidateComponents = scanner .findCandidateComponents(basePackage); 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); // 2.1 注册其Configuration类(如果有的话) // 本例中使用的是默认的Configuration,就不再分析该段代码 registerClientConfiguration(registry, name, attributes.get("configuration")); // 2.2 并将类或接口本身注入到Spring中 registerFeignClient(registry, annotationMetadata, attributes); } } } }
4.registerFeignClient()方法的分析
private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map<String, Object> attributes) { // 1.获取类名称,也就是本例中的FeignService接口 String className = annotationMetadata.getClassName(); // 2.BeanDefinitionBuilder的主要作用就是构建一个AbstractBeanDefinition // AbstractBeanDefinition类最终被构建成一个BeanDefinitionHolder // 然后注册到Spring中 // 注意:beanDefinition类为FeignClientFactoryBean,故在Spring获取类的时候实际返回的是 // FeignClientFactoryBean类 BeanDefinitionBuilder definition = BeanDefinitionBuilder .genericBeanDefinition(FeignClientFactoryBean.class); validate(attributes); // 3.添加FeignClientFactoryBean的属性, // 这些属性也都是我们在@FeignClient中定义的属性 definition.addPropertyValue("url", getUrl(attributes)); definition.addPropertyValue("path", getPath(attributes)); String name = getName(attributes); definition.addPropertyValue("name", name); 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); // 4.设置别名 name就是我们在@FeignClient中定义的name属性 String alias = name + "FeignClient"; AbstractBeanDefinition beanDefinition = definition.getBeanDefinition(); boolean primary = (Boolean)attributes.get("primary"); // has a default, won't be null beanDefinition.setPrimary(primary); String qualifier = getQualifier(attributes); if (StringUtils.hasText(qualifier)) { alias = qualifier; } // 5.定义BeanDefinitionHolder, // 在本例中 名称为FeignService,类为FeignClientFactoryBean BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, new String[] { alias }); BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry); }
通过分析可知:我们最终是向Spring中注册了一个bean,bean的名称就是类或接口的名称(也就是本例中的FeignService),bean的实现类是FeignClientFactoryBean,其属性设置就是我们在@FeignClient中定义的属性
那么下面我们在Controller中对FeignService的的引入,实际就是引入了FeignClientFactoryBean类
5.FeignClientFactoryBean的分析
其实现了FactoryBean接口,那么当从ApplicationContext中获取该bean的时候,实际调用的是其getObject()方法
class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean, ApplicationContextAware{ public Object getObject() throws Exception { // 1.获取容器中的FeignContext实现 // 默认实现在FeignAutoConfiguration类中 FeignContext context = applicationContext.getBean(FeignContext.class); // 2.主要使用构造者模式来构建一个Feign // 在1)中详细分析 Feign.Builder builder = feign(context); // 3.本例中没有指定URL,故执行if if (!StringUtils.hasText(this.url)) { String url; if (!this.name.startsWith("http")) { url = "http://" + this.name; } else { url = this.name; } url += cleanPath(); // 4.关键方法 // 在2)中详细分析 return loadBalance(builder, context, new HardCodedTarget<>(this.type, this.name, url)); } if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) { this.url = "http://" + this.url; } String url = this.url + cleanPath(); Client client = getOptional(context, Client.class); if (client != null) { if (client instanceof LoadBalancerFeignClient) { // not lod balancing because we have a url, // but ribbon is on the classpath, so unwrap client = ((LoadBalancerFeignClient)client).getDelegate(); } builder.client(client); } Targeter targeter = get(context, Targeter.class); return targeter.target(this, builder, context, new HardCodedTarget<>( this.type, this.name, url)); } }
5.1.feign(context)构造者模式构建Feign.Builder
protected Feign.Builder feign(FeignContext context) { FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class); Logger logger = loggerFactory.create(this.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 // 下面的几项getOptional()主要功能就是从ApplicationContext中获取对应类的实现 // 这些类用户可自定义,默认的话是从FeignAutoConfiguration中获取对应bean Logger.Level level = getOptional(context, Logger.Level.class); if (level != null) { builder.logLevel(level); } Retryer retryer = getOptional(context, Retryer.class); if (retryer != null) { builder.retryer(retryer); } ErrorDecoder errorDecoder = getOptional(context, ErrorDecoder.class); if (errorDecoder != null) { builder.errorDecoder(errorDecoder); } Request.Options options = getOptional(context, Request.Options.class); if (options != null) { builder.options(options); } Map<String, RequestInterceptor> requestInterceptors = context.getInstances( this.name, RequestInterceptor.class); if (requestInterceptors != null) { builder.requestInterceptors(requestInterceptors.values()); } if (decode404) { builder.decode404(); } return builder; }
5.2 loadBalance(builder, context, new HardCodedTarget<>(this.type,this.name, url))获取负载均衡后的对象
protected <T> T loadBalance(Feign.Builder builder, FeignContext context, HardCodedTarget<T> target) { // 1.获取Client的实现类,默认为LoadBalancerFeignClient类 // 实现在FeignRibbonClientAutoConfiguration中 Client client = getOptional(context, Client.class); if (client != null) { // 2.将LoadBalancerFeignClient包装到Feign.Builder builder.client(client); // 3.获取ApplicationContext中的Targeter实现 // 默认实现为HystrixTargeter,实现在FeignAutoConfiguration类中 Targeter targeter = get(context, Targeter.class); // 4.重点在这里 // 我们来看下这个方法 return targeter.target(this, builder, context, target); } ... } // HystrixTargeter.target() public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context, Target.HardCodedTarget<T> target) { // Feign.Builder为feign包路径下,不是 feign.hystrix.HystrixFeign.Builder,故直接走return方法 if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) { // 我们来看下这个方法,在feign.Feign.Builder类中 return feign.target(target); } ... } // feign.Feign.Builder.target(target) public <T> T target(Target<T> target) { return build().newInstance(target); } // feign.Feign.Builder.build() public Feign build() { // 注意这个工厂类,下面还是会用到的 SynchronousMethodHandler.Factory synchronousMethodHandlerFactory = new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger, logLevel, decode404); ParseHandlersByName handlersByName = new ParseHandlersByName(contract, options, encoder, decoder, errorDecoder, synchronousMethodHandlerFactory); // 在这里可以看到真正返回的是ReflectiveFeign return new ReflectiveFeign(handlersByName, invocationHandlerFactory); } // ReflectiveFeign.newInstance(target) public <T> T newInstance(Target<T> target) { // 1.分析出具体方法和对应的Handler处理, 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))); } } // 2.由factory创建一个InvocationHandler,实现为FeignInvocationHandler // 可知其代理的target为HardCodedTarget InvocationHandler handler = factory.create(target, methodToHandler); // 3.可以看到最终返回的是一个代理 T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(), new Class<?>[]{target.type()}, handler); for(DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) { defaultMethodHandler.bindTo(proxy); } return proxy; }
由以上分析可知,FeignClientFactoryBean.getObject()具体返回的是一个代理类,具体为FeignInvocationHandler
6. FeignInvocationHandler接收请求方法过程分析
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 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(); } // 非Object方法,则默认执行该句 // dispatch为map,方法的实现类为SynchronousMethodHandler // 我们来分析SynchronousMethodHandler.invoke()方法 return dispatch.get(method).invoke(args); }
6.1 SynchronousMethodHandler.invoke()
public Object invoke(Object[] argv) throws Throwable { // 1.根据请求参数创建一个feign.RequestTemplate RequestTemplate template = buildTemplateFromArgs.create(argv); // 2.用户定义的重试策略 Retryer retryer = this.retryer.clone(); while (true) { try { // 重要方法在这里 return executeAndDecode(template); } catch (RetryableException e) { retryer.continueOrPropagate(e); if (logLevel != Logger.Level.NONE) { logger.logRetry(metadata.configKey(), logLevel); } continue; } } }
6.2 executeAndDecode(template)执行请求
Object executeAndDecode(RequestTemplate template) throws Throwable { // 1.封装请求信息,feign.Request,会将请求封装为以下信息 // GET http://part-1-sms-interface/sms/test HTTP/1.1 Request request = targetRequest(template); if (logLevel != Logger.Level.NONE) { logger.logRequest(metadata.configKey(), logLevel, request); } Response response; long start = System.nanoTime(); try { // 2.真正的执行在这里 // client为LoadBalancerFeignClient // 继续在6.3中详细分析 response = client.execute(request, options); // ensure the request is set. TODO: remove in Feign 10 response.toBuilder().request(request).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); // 响应处理 ... }
6.3.LoadBalancerFeignClient.execute(request, options)请求负载均衡
public Response execute(Request request, Request.Options options) throws IOException { try { // 1.获取URI URI asUri = URI.create(request.url()); String clientName = asUri.getHost(); URI uriWithoutHost = cleanUrl(request.url(), clientName); // 2.封装成RibbonRequest请求 FeignLoadBalancer.RibbonRequest ribbonRequest = new FeignLoadBalancer.RibbonRequest( this.delegate, request, uriWithoutHost); // 3.封装请求参数信息 IClientConfig requestConfig = getClientConfig(options, clientName); // 4.执行请求,并进行负载均衡 // 本方法可分为三步: // 1)lbClient(clientName)获取执行类,本例中为FeignLoadBalancer // 2)FeignLoadBalancer.executeWithLoadBalancer()执行请求 // 3)toResponse()获取响应 return lbClient(clientName).executeWithLoadBalancer(ribbonRequest, requestConfig).toResponse(); } catch (ClientException e) { IOException io = findIOException(e); if (io != null) { throw io; } throw new RuntimeException(e); } }
6.4 FeignLoadBalancer.executeWithLoadBalancer()执行请求
public T executeWithLoadBalancer(final S request, final IClientConfig requestConfig) throws ClientException { RequestSpecificRetryHandler handler = getRequestSpecificRetryHandler(request, requestConfig); LoadBalancerCommand<T> command = LoadBalancerCommand.<T>builder() .withLoadBalancerContext(this) .withRetryHandler(handler) .withLoadBalancerURI(request.getUri()) .build(); try { // 在这里可以看到Hystrix的相关代码, return command.submit( new ServerOperation<T>() { @Override public Observable<T> call(Server server) { URI finalUri = reconstructURIWithServer(server, request.getUri()); S requestForServer = (S) request.replaceUri(finalUri); try { // 执行ribbon负载均衡请求 return Observable.just(AbstractLoadBalancerAwareClient.this.execute(requestForServer, requestConfig)); } catch (Exception e) { return Observable.error(e); } } }) .toBlocking() .single(); } catch (Exception e) { Throwable t = e.getCause(); if (t instanceof ClientException) { throw (ClientException) t; } else { throw new ClientException(e); } } }
- Spring Cloud Feign源码解析
- spring cloud openfeign 源码实例解析
- SpringCloud Feign源码解析
- spring cloud feign 运用与源码解析
- 网关 Spring-Cloud-Gateway 源码解析 —— 网关初始化
- SpringCloud项目集成Feign、Hystrix过程解析
- 十、Spring cloud服务短路(Hystrix)之源码解析
- Spring Cloud源码解析一:Eureka源码解析(F版)
- 网关 Spring-Cloud-Gateway 源码解析 —— 网关初始化
- springcloud 入门 5 (feign源码分析)
- Spring Cloud Feign组件实例解析
- 网关 Spring-Cloud-Gateway 源码解析 —— 网关初始化
- 【SpringCloud】Netflix源码解析之Ribbon:负载均衡策略的定义和实现
- 网关 Spring-Cloud-Gateway 源码解析 —— 调试环境搭建
- 网关 Spring-Cloud-Gateway 源码解析 —— 网关初始化
- spring-cloud源码解析-zuul路由的部分源码解析
- 网关 Spring-Cloud-Gateway 源码解析 —— 调试环境搭建
- Spring Cloud 之feign源码阅读
- Spring-cloud & Netflix 源码解析:Eureka 服务注册发现接口 ****
- 网关 Spring-Cloud-Gateway 源码解析 —— 网关初始化