OpenFeign源码分析
使用
compile 'org.springframework.cloud:spring-cloud-starter-openfeign'
@SpringBootApplication @EnableFeignClients(basePackages = {"com.yue.consumer"}) //开启 Feign支持,扫描指定包下接口 public class WebApplication { public static void main(String[] args) { SpringApplication.run(WebApplication.class, args); } //声明 feign接口 @FeignClient(name = "service-name", path = "/v1", url = "http://sck-demo-provider", primary = false) static interface FeignService { //调用服务接口 @RequestMapping("/test") public String getName(); } }
@RestController @RequestMapping("/test") public class TestController { @Autowired FeignService feignService; @RequestMapping("/getString") public String getStr(){ return feignService.getName(); } }
使用注意事项
多个参数传递问题
一般我们会使用@GetMapping和@PostMapping两种方式来调用Rest服务。
而接收的参数则会使用@RequestParam和@RequestBody来获取。
@RequestBody只能用在Post请求,并且一个Post请求只能有一个@RequestBody。 @RequestBody的参数可以包括复杂类型。
@RequestParam可以用在Post和Get请求中,但是! @RequestParam 的参数只能是基本类型或者Enum,或者List和Map(List和Map里面也只能是基本类型)。所以@RequestParam可以和@RequestBody一起使用。
如果我们是Get请求,但是又有复合类型怎么办? 比如我们想传递一个User对象。User对象里面只有普通的两个String属性。 这里我们可以使用@SpringQueryMap:
@GetMapping("getUserAge")
public String getUserAge(@RequestParam("userId") String userId, @SpringQueryMap User user);
注意:@SpringQueryMap后面的参数只能是普通的POJO,不能是复合类型,否则解析不了。如果必须使用复合类型,那么使用@RequestBody吧。
注册
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Import(FeignClientsRegistrar.class) public @interface EnableFeignClients { /** * basePackages 属性的别名。 允许使用更简洁的注释声明 */ String[] value() default {}; /** * 扫描包下带注释的组件 */ String[] basePackages() default {}; /** * basePackages() 的类型安全的替代方法,用于指定要扫描带注释的组件的软件包。 指定类别的包装将被扫描。 */ Class<?>[] basePackageClasses() default {}; /** * 适用于所有自定义@Configuration,可以包含组成客户端的部分的@Bean */ Class<?>[] defaultConfiguration() default {}; /** * 用@FeignClient注释的类的列表。 如果不为空,则禁用类路径*扫描。 */ Class<?>[] clients() default {}; }
FeignClientsRegistrar.class
class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware { // 获取 name static String getName(String name) { if (!StringUtils.hasText(name)) { return ""; } String host = null; try { String url; if (!name.startsWith("http://") && !name.startsWith("https://")) { url = "http://" + name; } else { url = name; } host = new URI(url).getHost(); } catch (URISyntaxException e) { } Assert.state(host != null, "Service id not legal hostname (" + name + ")"); return name; } //获取 url static String getUrl(String url) { if (StringUtils.hasText(url) && !(url.startsWith("#{") && url.contains("}"))) { if (!url.contains("://")) { url = "http://" + url; } try { new URL(url); } catch (MalformedURLException e) { throw new IllegalArgumentException(url + " is malformed", e); } } return url; } //获取 path static String getPath(String path) { if (StringUtils.hasText(path)) { path = path.trim(); if (!path.startsWith("/")) { path = "/" + path; } if (path.endsWith("/")) { path = path.substring(0, path.length() - 1); } } return path; } @Override public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { //注册configuration registerDefaultConfiguration(metadata, registry); //注册FeignClients registerFeignClients(metadata, registry); } private void registerDefaultConfiguration(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { Map<String, Object> defaultAttrs = metadata .getAnnotationAttributes(EnableFeignClients.class.getName(), true); if (defaultAttrs != null && defaultAttrs.containsKey("defaultConfiguration")) { String name; if (metadata.hasEnclosingClass()) { name = "default." + metadata.getEnclosingClassName(); } else { name = "default." + metadata.getClassName(); } //注册客户端配置 registerClientConfiguration(registry, name, defaultAttrs.get("defaultConfiguration")); } } private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object configuration) { //加载FeignClientSpecification bean BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FeignClientSpecification.class); builder.addConstructorArgValue(name); builder.addConstructorArgValue(configuration); //注册 registry.registerBeanDefinition(name + "." + FeignClientSpecification.class.getSimpleName(),builder.getBeanDefinition()); } public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { ClassPathScanningCandidateComponentProvider scanner = getScanner(); scanner.setResourceLoader(this.resourceLoader); Set<String> basePackages; Map<String, Object> attrs = metadata .getAnnotationAttributes(EnableFeignClients.class.getName()); // 扫描带有FeignClient注解的类 AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(FeignClient.class); //获取@EnableFeignClients 中clients的值 final Class<?>[] clients = attrs == null ? null : (Class<?>[]) attrs.get("clients"); if (clients == null || clients.length == 0) { //如果没有设置,那么设置类型过滤器 scanner.addIncludeFilter(annotationTypeFilter); // 如果没有设置,则扫描的包路径为 @EnableFeignClients 注解所在的包 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))); } //循环扫描注册 for (String basePackage : basePackages) { Set<BeanDefinition> candidateComponents = scanner .findCandidateComponents(basePackage); for (BeanDefinition candidateComponent : candidateComponents) { if (candidateComponent instanceof AnnotatedBeanDefinition) { // 验证带注释的类必须是接口 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")); //注册 FeignClient registerFeignClient(registry, annotationMetadata, attributes); } } } } private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map<String, Object> attributes) { String className = annotationMetadata.getClassName(); //将属性设置到 FeignClientFactoryBean 中 BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class); validate(attributes); 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")); //设置 Autowire类型 definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); String alias = contextId + "FeignClient"; AbstractBeanDefinition beanDefinition = definition.getBeanDefinition(); beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, className); // has a default, won't be null boolean primary = (Boolean) attributes.get("primary"); beanDefinition.setPrimary(primary); String qualifier = getQualifier(attributes); if (StringUtils.hasText(qualifier)) { alias = qualifier; } //注册 BeanDefinition BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, new String[] { alias }); BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry); } }
至此,注册完成,注意此时仅仅只是注册到 DefaultListableBeanFactory容器的 beanDefinitionMap中,并没有实例化!
实例化创建
@RestController @RequestMapping("/test") public class TestController { @Autowired FeignService feignService; @RequestMapping("/getString") public String getStr(){ return feignService.getName(); } }
在实例化 TestController 这个Bean后的填充属性阶段会去注入 FeignService 这个Bean。
如果你熟悉Spring 源码,那么知道 Bean的创建最终是通过 factory.getObject() 实现。
通过栈信息,可以很清晰的了解
FeignClient 的实例化 :factory.getObject() 是使用 FeignClientFactoryBean 类。
FeignClientFactoryBean.class
class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean, ApplicationContextAware { @Override public Object getObject() throws Exception { return getTarget(); } <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)); } if (StringUtils.hasText(url) && !url.startsWith("http")) { url = "http://" + url; } String url = this.url + cleanPath(); Client client = getOptional(context, Client.class); if (client != null) { if (client instanceof LoadBalancerFeignClient) { // not load balancing because we have a url, // but ribbon is on the classpath, so unwrap client = ((LoadBalancerFeignClient) client).getDelegate(); } if (client instanceof FeignBlockingLoadBalancerClient) { // not load balancing because we have a url, // but Spring Cloud LoadBalancer is on the classpath, so unwrap client = ((FeignBlockingLoadBalancerClient) client).getDelegate(); } builder.client(client); } Targeter targeter = get(context, Targeter.class); return (T) targeter.target(this, builder, context, new HardCodedTarget<>(type, name, 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 configureFeign(context, builder); return builder; } // 获取 Targeter protected <T> T get(FeignContext context, Class<T> type) { T instance = context.getInstance(contextId, type); if (instance == null) { throw new IllegalStateException( "No bean found of type " + type + " for " + contextId); } return instance; } 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); } throw new IllegalStateException( "No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-netflix-ribbon?"); } }
FeignClientFactoryBean
的getTarget
方法最后都是调用Target
的target
方法来获取实现该接口的实例。
Target
的实现有两个:DefaultTargeter
和 HystrixTargeter.
在实例化之前在回顾下Spring SPI机制。
FeignAutoConfiguration.class
@Configuration(proxyBeanMethods = false) @ConditionalOnClass(Feign.class) @EnableConfigurationProperties({ FeignClientProperties.class, FeignHttpClientProperties.class }) @Import(DefaultGzipDecoderConfiguration.class) public class FeignAutoConfiguration { //如果配置了 feign.hystrix.HystrixFeign属性则加载此配置 @Configuration(proxyBeanMethods = false) @ConditionalOnClass(name = "feign.hystrix.HystrixFeign") protected static class HystrixFeignTargeterConfiguration { @Bean @ConditionalOnMissingBean public Targeter feignTargeter() { return new HystrixTargeter(); } } //如果没有配置 feign.hystrix.HystrixFeign属性则加载此配置 @Configuration(proxyBeanMethods = false) @ConditionalOnMissingClass("feign.hystrix.HystrixFeign") protected static class DefaultFeignTargeterConfiguration { @Bean @ConditionalOnMissingBean public Targeter feignTargeter() { return new DefaultTargeter(); } } }
FeignClientsConfiguration.class
@Configuration(proxyBeanMethods = false) @ConditionalOnClass({ HystrixCommand.class, HystrixFeign.class }) protected static class HystrixFeignConfiguration { @Bean @Scope("prototype") @ConditionalOnMissingBean @ConditionalOnProperty(name = "feign.hystrix.enabled") public Feign.Builder feignHystrixBuilder() { return HystrixFeign.builder(); } }
HystrixTargeter.class 获取实例
class HystrixTargeter implements Targeter { @Override public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context, Target.HardCodedTarget<T> target) { 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); } Class<?> fallback = factory.getFallback(); if (fallback != void.class) {
// 如果有配置 fallback return targetWithFallback(name, context, target, builder, fallback); } Class<?> fallbackFactory = factory.getFallbackFactory(); if (fallbackFactory != void.class) {
// 如果有配置 fallBackFactory return targetWithFallbackFactory(name, context, target, builder, fallbackFactory); } //Fallback 的优先级大于 FallbackFactory, 它们最终都是调用 HystrixFeign.target方法 return feign.target(target); } }
HystrixFeign.class
public final class HystrixFeign { public <T> T target(Target<T> target, T fallback) { return build(fallback != null ? new FallbackFactory.Default<T>(fallback) : null) .newInstance(target); } public <T> T target(Target<T> target, FallbackFactory<? extends T> fallbackFactory) {
// 最终是在ReflectiveFeign 实现. return build(fallbackFactory).newInstance(target); } Feign build(final FallbackFactory<?> nullableFallbackFactory) { super.invocationHandlerFactory(new InvocationHandlerFactory() { @Override public InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch) { return new HystrixInvocationHandler(target, dispatch, setterFactory, nullableFallbackFactory); } }); super.contract(new HystrixDelegatingContract(contract)); return super.build(); } }
HystrixInvocationHandler.class
final class HystrixInvocationHandler implements InvocationHandler { private final Target<?> target; private final Map<Method, MethodHandler> dispatch; private final FallbackFactory<?> fallbackFactory; // Nullable private final Map<Method, Method> fallbackMethodMap; private final Map<Method, Setter> setterMethodMap; HystrixInvocationHandler(Target<?> target, Map<Method, MethodHandler> dispatch, SetterFactory setterFactory, FallbackFactory<?> fallbackFactory) { this.target = checkNotNull(target, "target"); this.dispatch = checkNotNull(dispatch, "dispatch"); this.fallbackFactory = fallbackFactory; this.fallbackMethodMap = toFallbackMethod(dispatch); this.setterMethodMap = toSetters(setterFactory, target, dispatch.keySet()); } }
HystrixFeign父类 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); return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder); }
ReflectiveFeign.class
public class ReflectiveFeign extends Feign { private final ParseHandlersByName targetToHandlersByName; private final InvocationHandlerFactory factory; private final QueryMapEncoder queryMapEncoder; ReflectiveFeign(ParseHandlersByName targetToHandlersByName, InvocationHandlerFactory factory, QueryMapEncoder queryMapEncoder) { this.targetToHandlersByName = targetToHandlersByName; this.factory = factory; this.queryMapEncoder = queryMapEncoder; } @Override public <T> T newInstance(Target<T> target) {
// 创建MethodHandler
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))); } }
// JDK动态代理 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; } }
static final class ParseHandlersByName { // 创建 MethodHandler public Map<String, MethodHandler> apply(Target target) { // 解析接口的方法,生成MethodMetadata实例, List<MethodMetadata> metadata = contract.parseAndValidateMetadata(target.type()); Map<String, MethodHandler> result = new LinkedHashMap<String, MethodHandler>(); // 遍历接口方法 for (MethodMetadata md : metadata) { BuildTemplateByResolvingArgs buildTemplate; if (!md.formParams().isEmpty() && md.template().bodyTemplate() == null) { buildTemplate = new BuildFormEncodedTemplateFromArgs(md, encoder, queryMapEncoder, target); } else if (md.bodyIndex() != null) { buildTemplate = new BuildEncodedTemplateFromArgs(md, encoder, queryMapEncoder, target); } else { buildTemplate = new BuildTemplateByResolvingArgs(md, queryMapEncoder, target); } if (md.isIgnored()) { result.put(md.configKey(), args -> { throw new IllegalStateException(md.configKey() + " is not a method handled by feign"); }); } else { // 调用Factory实例的create方法来创建MethodHandler result.put(md.configKey(), factory.create(target, md, buildTemplate, options, decoder, errorDecoder)); } } return result; } }
解析接口
public class SpringMvcContract extends Contract.BaseContract implements ResourceLoaderAware { @Override public MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method) { processedMethods.put(Feign.configKey(targetType, method), method); MethodMetadata md = super.parseAndValidateMetadata(targetType, method); RequestMapping classAnnotation = findMergedAnnotation(targetType, RequestMapping.class); if (classAnnotation != null) { // 生产-仅当方法未指定时才使用类注释 if (!md.template().headers().containsKey(ACCEPT)) { parseProduces(md, method, classAnnotation); } // 消费-仅在方法未指定时才从类注释中使用 if (!md.template().headers().containsKey(CONTENT_TYPE)) { parseConsumes(md, method, classAnnotation); } // 标头-类批注继承到方法,请始终将其写入(如果存在) parseHeaders(md, method, classAnnotation); } return md; } //处理类上的 @RequestMapping 注解 @Override protected void processAnnotationOnClass(MethodMetadata data, Class<?> clz) { if (clz.getInterfaces().length == 0) { RequestMapping classAnnotation = findMergedAnnotation(clz, RequestMapping.class); if (classAnnotation != null) { // 如果指定,则从类注释添加路径 if (classAnnotation.value().length > 0) { String pathValue = emptyToNull(classAnnotation.value()[0]); pathValue = resolve(pathValue); if (!pathValue.startsWith("/")) { pathValue = "/" + pathValue; } data.template().uri(pathValue); if (data.template().decodeSlash() != decodeSlash) { data.template().decodeSlash(decodeSlash); } } } } } //处理方法上的 @RequestMapping 注解 @Override protected void processAnnotationOnMethod(MethodMetadata data, Annotation methodAnnotation, Method method) { if (CollectionFormat.class.isInstance(methodAnnotation)) { CollectionFormat collectionFormat = findMergedAnnotation(method, CollectionFormat.class); data.template().collectionFormat(collectionFormat.value()); } if (!RequestMapping.class.isInstance(methodAnnotation) && !methodAnnotation.annotationType().isAnnotationPresent(RequestMapping.class)) { return; } RequestMapping methodMapping = findMergedAnnotation(method, RequestMapping.class); // 获取请求方法 RequestMethod[] methods = methodMapping.method(); if (methods.length == 0) { methods = new RequestMethod[] { RequestMethod.GET }; } checkOne(method, methods, "method"); data.template().method(Request.HttpMethod.valueOf(methods[0].name())); // path checkAtMostOne(method, methodMapping.value(), "value"); if (methodMapping.value().length > 0) { String pathValue = emptyToNull(methodMapping.value()[0]); if (pathValue != null) { pathValue = resolve(pathValue); // Append path from @RequestMapping if value is present on method if (!pathValue.startsWith("/") && !data.template().path().endsWith("/")) { pathValue = "/" + pathValue; } data.template().uri(pathValue, true); if (data.template().decodeSlash() != decodeSlash) { data.template().decodeSlash(decodeSlash); } } } // produces parseProduces(data, method, methodMapping); // consumes parseConsumes(data, method, methodMapping); // headers parseHeaders(data, method, methodMapping); data.indexToExpander(new LinkedHashMap<>()); } // 处理参数上的注解 @Override protected boolean processAnnotationsOnParameter(MethodMetadata data, Annotation[] annotations, int paramIndex) { boolean isHttpAnnotation = false; AnnotatedParameterProcessor.AnnotatedParameterContext context = new SimpleAnnotatedParameterContext( data, paramIndex); Method method = processedMethods.get(data.configKey()); for (Annotation parameterAnnotation : annotations) { AnnotatedParameterProcessor processor = annotatedArgumentProcessors .get(parameterAnnotation.annotationType()); if (processor != null) { Annotation processParameterAnnotation; // synthesize, handling @AliasFor, while falling back to parameter name on // missing String #value(): processParameterAnnotation = synthesizeWithMethodParameterNameAsFallbackValue( parameterAnnotation, method, paramIndex); isHttpAnnotation |= processor.processArgument(context, processParameterAnnotation, method); } } if (!isMultipartFormData(data) && isHttpAnnotation && data.indexToExpander().get(paramIndex) == null) { TypeDescriptor typeDescriptor = createTypeDescriptor(method, paramIndex); if (conversionService.canConvert(typeDescriptor, STRING_TYPE_DESCRIPTOR)) { Param.Expander expander = convertingExpanderFactory .getExpander(typeDescriptor); if (expander != null) { data.indexToExpander().put(paramIndex, expander); } } } return isHttpAnnotation; } }
abstract class BaseContract implements Contract { protected MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method) { final MethodMetadata data = new MethodMetadata(); data.targetType(targetType); data.method(method); data.returnType(Types.resolve(targetType, targetType, method.getGenericReturnType())); data.configKey(Feign.configKey(targetType, method)); if (targetType.getInterfaces().length == 1) { processAnnotationOnClass(data, targetType.getInterfaces()[0]); }
// 调用子类处理方法 processAnnotationOnClass(data, targetType); for (final Annotation methodAnnotation : method.getAnnotations()) { processAnnotationOnMethod(data, methodAnnotation, method); } if (data.isIgnored()) { return data; } checkState(data.template().method() != null, "Method %s not annotated with HTTP method type (ex. GET, POST)%s", data.configKey(), data.warnings()); final Class<?>[] parameterTypes = method.getParameterTypes(); final Type[] genericParameterTypes = method.getGenericParameterTypes(); final Annotation[][] parameterAnnotations = method.getParameterAnnotations(); final int count = parameterAnnotations.length; for (int i = 0; i < count; i++) { boolean isHttpAnnotation = false; if (parameterAnnotations[i] != null) { isHttpAnnotation = processAnnotationsOnParameter(data, parameterAnnotations[i], i); } if (isHttpAnnotation) { data.ignoreParamater(i); } if (parameterTypes[i] == URI.class) { data.urlIndex(i); } else if (!isHttpAnnotation && parameterTypes[i] != Request.Options.class) { if (data.isAlreadyProcessed(i)) { checkState(data.formParams().isEmpty() || data.bodyIndex() == null, "Body parameters cannot be used with form parameters.%s", data.warnings()); } else { checkState(data.formParams().isEmpty(), "Body parameters cannot be used with form parameters.%s", data.warnings()); checkState(data.bodyIndex() == null, "Method has too many Body parameters: %s%s", method, data.warnings()); data.bodyIndex(i); data.bodyType(Types.resolve(targetType, targetType, genericParameterTypes[i])); } } } if (data.headerMapIndex() != null) { checkMapString("HeaderMap", parameterTypes[data.headerMapIndex()], genericParameterTypes[data.headerMapIndex()]); } if (data.queryMapIndex() != null) { if (Map.class.isAssignableFrom(parameterTypes[data.queryMapIndex()])) { checkMapKeys("QueryMap", genericParameterTypes[data.queryMapIndex()]); } } return data; } }
SynchronousMethodHandler.Factory Class
static class Factory { public MethodHandler create(Target<?> target, MethodMetadata md, RequestTemplate.Factory buildTemplateFromArgs, Options options, Decoder decoder, ErrorDecoder errorDecoder) { return new SynchronousMethodHandler(target, client, retryer, requestInterceptors, logger, logLevel, md, buildTemplateFromArgs, options, decoder, errorDecoder, decode404, closeAfterDecode, propagationPolicy, forceDecoding); } }
创建的MethodHandler
的类型是SynchronousMethodHandler
。因此,当我们调用接口的方法时,最终调用的是SynchronousMethodHandler
的invoke
方法。
调用
如果配置了feign.hystrix.enabled,那么在调用接口时则调用的 HystrixInvocationHandler 的 invoke 方法,用HystrixCommand进行包装,但最终还是使用 SynchronousMethodHandler 的 invoke 去调用最终的接口
如果没有配置则直接调用 SynchronousMethodHandler 的 invoke 方法。
feign: hystrix: enabled: true
HystrixInvocationHandler.class
@Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { // early exit if the invoked method is from java.lang.Object // code is the same as ReflectiveFeign.FeignInvocationHandler 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(); } // 使用HystrixCommand 包装 HystrixCommand<Object> hystrixCommand = new HystrixCommand<Object>(setterMethodMap.get(method)) { @Override protected Object run() throws Exception { try { // 调用 methodhandler 处理最终的请求,会调用 SynchronousMethodHandler 的 invoke 方法。 return HystrixInvocationHandler.this.dispatch.get(method).invoke(args); } catch (Exception e) { throw e; } catch (Throwable t) { throw (Error) t; } } @Override protected Object getFallback() { if (fallbackFactory == null) { return super.getFallback(); } try { // 获取 fallback 方法,并执行 Object fallback = fallbackFactory.create(getExecutionException()); Object result = fallbackMethodMap.get(method).invoke(fallback, args); if (isReturnsHystrixCommand(method)) { return ((HystrixCommand) result).execute(); } else if (isReturnsObservable(method)) { // Create a cold Observable return ((Observable) result).toBlocking().first(); } else if (isReturnsSingle(method)) { // Create a cold Observable as a Single return ((Single) result).toObservable().toBlocking().first(); } else if (isReturnsCompletable(method)) { ((Completable) result).await(); return null; } else if (isReturnsCompletableFuture(method)) { return ((Future) result).get(); } else { return result; } } catch (IllegalAccessException e) { ... } } }; ... return hystrixCommand.execute(); }
SynchronousMethodHandler.class
@Override public Object invoke(Object[] argv) throws Throwable { // 从Args构建模板 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 { Request request = targetRequest(template); if (logLevel != Logger.Level.NONE) { logger.logRequest(metadata.configKey(), logLevel, request); } Response response; long start = System.nanoTime(); try {
// 如果导入了Ribbon负载均衡依赖,这个client就是 LoadBalancerFeignClient 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; } }
Client 执行最终的Requst 请求
默认处理:
class Default implements Client { private final SSLSocketFactory sslContextFactory; private final HostnameVerifier hostnameVerifier; @Override public Response execute(Request request, Request.Options options) throws IOException { HttpURLConnection connection = convertAndSend(request, options); return convertResponse(connection, request); } }
如果导入了Ribbon负载均衡依赖,这个client就是 LoadBalancerFeignClient
Spring Cloud 的负载均衡处理
public class LoadBalancerFeignClient implements Client { @Override public Response execute(Request request, Request.Options options) throws IOException { try { URI asUri = URI.create(request.url()); String clientName = asUri.getHost(); URI uriWithoutHost = cleanUrl(request.url(), clientName); //Ribbon整合就在这 //this.delegate 就是上面的feign.Client.Default.java //包装了一下先进行负载均衡,再进行远程调用,最终远程调用还是依靠this.delegate FeignLoadBalancer.RibbonRequest ribbonRequest = new FeignLoadBalancer.RibbonRequest( this.delegate, request, uriWithoutHost); IClientConfig requestConfig = getClientConfig(options, clientName); // lbClient: 获取负载均衡器 return lbClient(clientName) .executeWithLoadBalancer(ribbonRequest, requestConfig).toResponse(); } catch (ClientException e) { IOException io = findIOException(e); if (io != null) { throw io; } throw new RuntimeException(e); } } }
lbClient(clientName)
// lbClientFactory : CachingSpringLoadBalancerFactory // CachingSpringLoadBalancerFactory是在FeignRibbonClientAutoConfiguration.class 加载时创建 private FeignLoadBalancer lbClient(String clientName) { return this.lbClientFactory.create(clientName); } CachingSpringLoadBalancerFactory.class public FeignLoadBalancer create(String clientName) { // 先从缓存获取 FeignLoadBalancer client = this.cache.get(clientName); if (client != null) { return client; } IClientConfig config = this.factory.getClientConfig(clientName); // 创建负载均衡器 // this.factory : SpringClientFactory; 在RiboonAutoConfiguration.class 加载时创建 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; } SpringClientFactory.class // 默认情况下使用 ZoneAwareLoadBalancer : RibbonClientConfiguration.class 加载时创建 public class SpringClientFactory extends NamedContextFactory<RibbonClientSpecification> { public ILoadBalancer getLoadBalancer(String name) { return getInstance(name, ILoadBalancer.class); } @Override public <C> C getInstance(String name, Class<C> type) { C instance = super.getInstance(name, type); if (instance != null) { return instance; } IClientConfig config = getInstance(name, IClientConfig.class); return instantiateWithConfig(getContext(name), type, config); } }
executeWithLoadBalancer(...)
AbstractLoadBalancerAwareClient.class 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) { URI finalUri = reconstructURIWithServer(server, request.getUri()); S requestForServer = (S) request.replaceUri(finalUri); try { 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); } } }
LoadBalancerCommand.class public Observable<T> submit(final ServerOperation<T> operation) { final ExecutionInfoContext context = new ExecutionInfoContext(); if (listenerInvoker != null) { try { listenerInvoker.onExecutionStart(); } catch (AbortExecutionException e) { return Observable.error(e); } } final int maxRetrysSame = retryHandler.getMaxRetriesOnSameServer(); final int maxRetrysNext = retryHandler.getMaxRetriesOnNextServer(); // 使用负载均衡 Observable<T> o = (server == null ? selectServer() : Observable.just(server)) .concatMap(new Func1<Server, Observable<T>>() { @Override // 为每个选定的服务调用 public Observable<T> call(Server server) { context.setServer(server); final ServerStats stats = loadBalancerContext.getServerStats(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) { context.incAttemptCount(); loadBalancerContext.noteOpenConnection(stats); if (listenerInvoker != null) { try { listenerInvoker.onStartWithServer(context.toExecutionInfo()); } catch (AbortExecutionException e) { return Observable.error(e); } } final Stopwatch tracer = loadBalancerContext.getExecuteTracer().start(); // 调用 return operation.call(server).doOnEach(new Observer<T>() { private T entity; // 监听调用结果 @Override public void onCompleted() { recordStats(tracer, stats, entity, null); // TODO: What to do if onNext or onError are never called? } ...省略 }); } 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); } } }); }
LoadBalancerContext.class public Server getServerFromLoadBalancer(@Nullable URI original, @Nullable Object loadBalancerKey) throws ClientException { String host = null; int port = -1; if (original != null) { host = original.getHost(); } if (original != null) { Pair<String, Integer> schemeAndPort = deriveSchemeAndPortFromPartialUri(original); port = schemeAndPort.second(); } // 要使用的负载均衡器及其实例取决于注册方式。在每种情况下,客户端都可能使用完整网址或部分URL进入 ILoadBalancer lb = getLoadBalancer(); if (host == null) { // 部分URI或没有URI大小写 // 好吧,我们只能从lb获得正确的实例-否则我们就会fallback if (lb != null){ Server svc = lb.chooseServer(loadBalancerKey); if (svc == null){ throw new ClientException(ClientException.ErrorType.GENERAL, "Load balancer does not have available server for client: " + clientName); } host = svc.getHost(); if (host == null){ throw new ClientException(ClientException.ErrorType.GENERAL, "Invalid Server for :" + svc); } logger.debug("{} using LB returned Server: {} for request {}", new Object[]{clientName, svc, original}); return svc; } else { ...省略 return new Server(host, port); }
ZoneAwareLoadBalancer.class @Override public Server chooseServer(Object key) { // 区域感知逻辑已禁用或只有一个zone区域 if (!ENABLED.get() || getLoadBalancerStats().getAvailableZones().size() <= 1) { logger.debug("Zone aware logic disabled or there is only one zone"); return super.chooseServer(key); } Server server = null; try { LoadBalancerStats lbStats = getLoadBalancerStats(); Map<String, ZoneSnapshot> zoneSnapshot = ZoneAvoidanceRule.createSnapshot(lbStats); logger.debug("Zone snapshots: {}", zoneSnapshot); if (triggeringLoad == null) { triggeringLoad = DynamicPropertyFactory.getInstance().getDoubleProperty( "ZoneAwareNIWSDiscoveryLoadBalancer." + this.getName() + ".triggeringLoadPerServerThreshold", 0.2d); } if (triggeringBlackoutPercentage == null) { triggeringBlackoutPercentage = DynamicPropertyFactory.getInstance().getDoubleProperty( "ZoneAwareNIWSDiscoveryLoadBalancer." + this.getName() + ".avoidZoneWithBlackoutPercetage", 0.99999d); } // 可用zone不止一个的话获取所有可用的zone Set<String> availableZones = ZoneAvoidanceRule.getAvailableZones(zoneSnapshot, triggeringLoad.get(), triggeringBlackoutPercentage.get()); logger.debug("Available zones: {}", availableZones); if (availableZones != null && availableZones.size() < zoneSnapshot.keySet().size()) { String zone = ZoneAvoidanceRule.randomChooseZone(zoneSnapshot, availableZones); logger.debug("Zone chosen: {}", zone); if (zone != null) { // 获取对应zone的负载均衡器 BaseLoadBalancer zoneLoadBalancer = getLoadBalancer(zone); // 通过负载均衡器选择Server server = zoneLoadBalancer.chooseServer(key); } } } catch (Exception e) { logger.error("Error choosing server using zone aware logic for load balancer={}", name, e); } if (server != null) { return server; } else { logger.debug("Zone avoidance logic is not invoked."); return super.chooseServer(key); } }
BaseLoadBalancer.class public Server chooseServer(Object key) { if (counter == null) { counter = createCounter(); } counter.increment(); if (rule == null) { return null; } else { try { // 根据负载均衡的策略选择服务,rule默认是轮询算法RoundRobinRule return rule.choose(key); } catch (Exception e) { logger.warn("LoadBalancer [{}]: Error choosing server for key {}", name, key, e); return null; } } }
负载均衡策略:
默认轮询策略: RoundRobinRule
RoundRobinRule.class public Server choose(ILoadBalancer lb, Object key) { if (lb == null) { log.warn("no load balancer"); return null; } Server server = null; int count = 0; while (server == null && count++ < 10) { //获取所有能够到达的Server,其实就是UP状态的Server! List<Server> reachableServers = lb.getReachableServers(); List<Server> allServers = lb.getAllServers(); int upCount = reachableServers.size(); int serverCount = allServers.size(); if ((upCount == 0) || (serverCount == 0)) { log.warn("No up servers available from load balancer: " + lb); return null; } //轮询方式获取一个索引 int nextServerIndex = incrementAndGetModulo(serverCount); //从所有Server集合中获取Server server = allServers.get(nextServerIndex); //如果Server为空,就歇会儿。 if (server == null) { /* Transient. */ Thread.yield(); continue; } //判断是否可用、状态是否准备好了 if (server.isAlive() && (server.isReadyToServe())) { return (server); } // Next.不可用或者没准备好,进入下一次循环 server = null; } //负载均衡器尝试10次后,没有可用的活动服务器,返回null if (count >= 10) { log.warn("No available alive servers after 10 tries from load balancer: " + lb); } return server; }