SpringCloud openfeign源码分析

SpringCloud openfeign源码分析,第1张

SpringCloud openfeign源码分析

在分析源码前,还是先介绍一下简单的使用流程。

首先引入依赖


	org.springframework.cloud
	spring-cloud-starter-openfeign

开启自动Feign客户端功能

@SpringBootApplication
//可以配置扫描的Feign客户端包路径,不配置则为TestApplication.class包下
@EnableFeignClients
public class TestApplication {
    public static void main(String[] args) {
        SpringApplication.run(FeignApplication.class);
    }
}

定义FeignClient

//可以添加一些配置,例如服务名,url之类
@FeignClient
public interface TestFeignClient{
	
    //Spring MVC,调用地址要和服务提供方一致
    @RequestMapping
    public String geta();
    
}

openfeign的基本使用就是这样,然后加上自己所需要的配置即可。接下来就开始分析openfeign是如何开启,并如何实现远程调用的原理。

@EnableFeignClients开启Feign功能
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@documented
//FeignClients注册器
@import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {

    //注解的配置
	//......

}

//实现了importBeanDefinitionRegistrar接口,去看registerBeanDefinitions()方法
class FeignClientsRegistrar implements importBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware 
#FeignClientsRegistrar
public void registerBeanDefinitions(Annotationmetadata metadata,
		BeanDefinitionRegistry registry) {
    //注册@EnableFeignClients上定义的defaultConfiguration默认配置类
	registerDefaultConfiguration(metadata, registry);
    //扫描所有的@FeignClient注解
	registerFeignClients(metadata, registry);
}
注册默认配置类
#FeignClientsRegistrar
private void registerDefaultConfiguration(Annotationmetadata metadata,
		BeanDefinitionRegistry registry) {
    //获取@EnableFeignClients配置的信息
	Map defaultAttrs = metadata
			.getAnnotationAttributes(EnableFeignClients.class.getName(), true);
    //判断是否配置了defaultConfiguration
	if (defaultAttrs != null && defaultAttrs.containsKey("defaultConfiguration")) {
		String name;
        //判断配置在defaultConfiguration是否为内部类,拼接对应的类名
		if (metadata.hasEnclosingClass()) {
			name = "default." + metadata.getEnclosingClassName();
		}
		else {
			name = "default." + metadata.getClassName();
		}
        //跟进去
		registerClientConfiguration(registry, name,
				defaultAttrs.get("defaultConfiguration"));
	}
}

#FeignClientsRegistrar
private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name,
		Object configuration) {
	BeanDefinitionBuilder builder = BeanDefinitionBuilder
			.genericBeanDefinition(FeignClientSpecification.class);
	builder.addConstructorArgValue(name);
	builder.addConstructorArgValue(configuration);
    //将@EnableFeignClients中的配置信息注册到容器中
	registry.registerBeanDefinition(
			name + "." + FeignClientSpecification.class.getSimpleName(),
			builder.getBeanDefinition());
}
扫描@FeignClient注解
#FeignClientsRegistrar
public void registerFeignClients(Annotationmetadata metadata,
		BeanDefinitionRegistry registry) {
    //获取类路径扫描器
	ClassPathScanningCandidateComponentProvider scanner = getScanner();
    //设置资源加载器
	scanner.setResourceLoader(this.resourceLoader);
	Set basePackages;
    //获取@EnableFeignClients的注解信息
	Map 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) {
		scanner.addIncludeFilter(annotationTypeFilter);
        //获取包路径
		basePackages = getbasePackages(metadata);
	}
	else {
		//......
	}
    //遍历包路径
	for (String basePackage : basePackages) {
        //获取该包路径下带@FeignClient的BD信息
		Set 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");
                //获取@FeignClient的注解信息
				Map attributes = annotationmetadata
						.getAnnotationAttributes(
								FeignClient.class.getCanonicalName());
                //获取@FeignClient上配置的名称,优先级为contextId>value>name>serviceId
				String name = getClientName(attributes);
                //注册@FeignClient的配置信息
				registerClientConfiguration(registry, name,
						attributes.get("configuration"));
                //注册加了@FeignClient的类到容器中
				registerFeignClient(registry, annotationmetadata, attributes);
			}
		}
	}
}

#FeignClientsRegistrar
private void registerFeignClient(BeanDefinitionRegistry registry,
		Annotationmetadata annotationmetadata, Map attributes) {
    //返回添加了@FeignClient注解的Class的全限定名,  包名.类名
	String className = annotationmetadata.getClassName();
    //FeignClientFactoryBean是一个FactoryBean,用它来创建具体的FeignClient
	BeanDefinitionBuilder definition = BeanDefinitionBuilder
			.genericBeanDefinition(FeignClientFactoryBean.class);
	validate(attributes);
    //向FeignClientFactoryBean添加@FeignClient中配置的一些注解信息
	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"));
	definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
	String alias = contextId + "FeignClient";
	AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
	boolean primary = (Boolean) attributes.get("primary");
	beanDefinition.setPrimary(primary);
	String qualifier = getQualifier(attributes);
	if (StringUtils.hasText(qualifier)) {
		alias = qualifier;
	}
	BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,
			new String[] { alias });
    //将FeignClientFactoryBean注册到容器中
	BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
}

这一步完成后,所有的加了@FeignClient的类就会被解析成FeignClientFactoryBean类型的BeanDefinition加入到容器中,FeignClientFactoryBean包含了@FeignClient上配置的信息,以及保存了当前添加@FeignClient注解的Class名称。之后就是Spring容器在refresh()内会去实例化该FeignClient,而FeignClientFactoryBean是FactoryBean类型,所以会调用它的getObject()进行实例化。

FeignClient实例化
#FeignClientFactoryBean
public Object getObject() throws Exception {
	return getTarget();
}

#FeignClientFactoryBean
 T getTarget() {
    //获取FeignContext,在FeignAutoConfiguration自动装配进来
	FeignContext context = this.applicationContext.getBean(FeignContext.class);
    //创建builder对象,用来生成Feign
	Feign.Builder builder = feign(context);
    //如果没有在@FeignClient配置了url,说明要负载均衡
	if (!StringUtils.hasText(this.url)) {
       	//构造url
		if (!this.name.startsWith("http")) {
			this.url = "http://" + this.name;
		}
		else {
			this.url = this.name;
		}
        //http://服务名
		this.url += cleanPath();
        //创建负载均衡代理类
		return (T) loadBalance(builder, context,
				new HardCodedTarget<>(this.type, this.name, this.url));
	}
    
    //说明url存在,使用硬编码的方式
	if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {
        //直接拼接url
		this.url = "http://" + this.url;
	}
	String url = this.url + cleanPath();
    //获取客户端对象
	Client client = getOptional(context, Client.class);
	if (client != null) {
        //Ribbon客户端对象LoadBalancerFeignClient
		if (client instanceof LoadBalancerFeignClient) {
			client = ((LoadBalancerFeignClient) client).getDelegate();
		}
		builder.client(client);
	}
    //在FeignAutoConfiguration自动装配进来
	Targeter targeter = get(context, Targeter.class);
    //生成动态代理对象
	return (T) targeter.target(this, builder, context,
			new HardCodedTarget<>(this.type, this.name, url));
}

先来看看FeignAutoConfiguration都装配了什么Bean

FeignAutoConfiguration自动装配
@Configuration
@ConditionalOnClass(Feign.class)
@EnableConfigurationProperties({ FeignClientProperties.class,
		FeignHttpClientProperties.class })
public class FeignAutoConfiguration {
	
    //FeignContext,内部保存了创建FeignClient所需的组件
	@Bean
	public FeignContext feignContext() {
		FeignContext context = new FeignContext();
		context.setConfigurations(this.configurations);
		return context;
	}

    //以下是两个相对的条件
	@Configuration
	@ConditionalOnClass(name = "feign.hystrix.HystrixFeign")//引入hystrix
	protected static class HystrixFeignTargeterConfiguration {
		@Bean
		@ConditionalOnMissingBean
		public Targeter feignTargeter() {
            //创建Hystrix类型
			return new HystrixTargeter();
		}
	}

	@Configuration
	@ConditionalOnMissingClass("feign.hystrix.HystrixFeign")//未引入hystrix
	protected static class DefaultFeignTargeterConfiguration {
		@Bean
		@ConditionalOnMissingBean
		public Targeter feignTargeter() {
            //创建默认类型
			return new DefaultTargeter();
		}

	}
    
    //下面还有HttpClient,Okhttp的配置
}

FeignAutoConfiguration配置类会自动装配一些用来创建FeignClient实例的Bean信息。

创建生成Feign的Builder对象
#FeignClientFactoryBean
protected Feign.Builder feign(FeignContext context) {
	FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);
	Logger logger = loggerFactory.create(this.type);
    //设置Logger、Encoder、Decoder等组件
	Feign.Builder builder = get(context, Feign.Builder.class)
			.logger(logger)
			.encoder(get(context, Encoder.class))
			.decoder(get(context, Decoder.class))
			.contract(get(context, Contract.class));
    //配置builder
	configureFeign(context, builder);
	return builder;
}

#FeignClientFactoryBean
protected void configureFeign(FeignContext context, Feign.Builder builder) {
	FeignClientProperties properties = this.applicationContext
			.getBean(FeignClientProperties.class);
    //从.properties配置文件中加载配置
	if (properties != null) {
		if (properties.isDefaultToProperties()) {
			configureUsingConfiguration(context, builder);
			configureUsingProperties(
					properties.getConfig().get(properties.getDefaultConfig()),
					builder);
			configureUsingProperties(properties.getConfig().get(this.contextId),
					builder);
		}
		else {
			configureUsingProperties(
					properties.getConfig().get(properties.getDefaultConfig()),
					builder);
			configureUsingProperties(properties.getConfig().get(this.contextId),
					builder);
			configureUsingConfiguration(context, builder);
		}
	}
    //配置类@Bean加载配置
	else {
		configureUsingConfiguration(context, builder);
	}
}

在加载配置到builder对象中后,就是去生成代理对象的逻辑。

创建Feign代理对象

首先来看看创建负载均衡代理对象

#FeignClientFactoryBean
protected  T loadBalance(Feign.Builder builder, FeignContext context,
		HardCodedTarget target) {
    //获取客户端对象
	Client client = getOptional(context, Client.class);
	if (client != null) {
		builder.client(client);
        //获取Targeter,分别有HystrixTargeter和DefaultTargeter类型
		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?");
}

先分析DefaultTargeter类型的代理对象

DefaultTargeter创建代理对象
#DefaultTargeter
public  T target(FeignClientFactoryBean factory, Feign.Builder feign,
      FeignContext context, Target.HardCodedTarget target) {
   return feign.target(target);
}

#Feign
public  T target(Target target) {
    //跟进去
   return build().newInstance(target);
}

#Feign.Builder
public Feign build() {
  //构建SynchronousMethodHandler工厂
  SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
      new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
          logLevel, decode404, closeAfterDecode, propagationPolicy);
  //设置组件对象
  ParseHandlersByName handlersByName =
      new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,
          errorDecoder, synchronousMethodHandlerFactory);
  //创建ReflectiveFeign实例,invocationHandlerFactory是InvocationHandlerFactory.Default类型
  return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
}

#ReflectiveFeign  是Feign的实现类
public  T newInstance(Target target) {
  //target内部保存了当前加了@FeignClient的接口Class,apply()会解析出接口中的方法和方法上的注解
  //key是方法名,value是SynchronousMethodHandler类型,内部持有这个方法和注解的所有信息
  Map nameToHandler = targetToHandlersByName.apply(target);
  Map methodToHandler = new linkedHashMap();
  List defaultMethodHandlers = new linkedList();
  //target.type()就是获取接口的Class
  //遍历所有的接口方法
  for (Method method : target.type().getMethods()) {
    if (method.getDeclaringClass() == Object.class) {
      //Object的方法不管
      continue;
    } else if (Util.isDefault(method)) {
      //default 类型的方法,要加入到defaultMethodHandlers集合
      DefaultMethodHandler handler = new DefaultMethodHandler(method);
      defaultMethodHandlers.add(handler);
      methodToHandler.put(method, handler);
    } else {
      //非Object,default的方法,从nameToHandler中取出添加到methodToHandler集合
      methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
    }
  }
  //InvocationHandler工厂创建InvocationHandler对象
  InvocationHandler handler = factory.create(target, methodToHandler);
  //创建代理对象
  T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
      new Class[] {target.type()}, handler);
  for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
    //将default方法绑定在代理对象上
    defaultMethodHandler.bindTo(proxy);
  }
  //返回代理对象
  return proxy;
}

到这里代理对象也创建完成了,接下来就该去看看InvocationHandler的invoke方法是在哪实现的。

InvocationHandler对象调用invoke()
#InvocationHandlerFactory.Default
public InvocationHandler create(Target target, Map dispatch) {
  //创建了FeignInvocationHandler类型的InvocationHandler,直接看它的invoke方法
  return new ReflectiveFeign.FeignInvocationHandler(target, dispatch);
}

#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();
  }
  //dispatch就是在构造中赋值的,在#ReflectiveFeign的newInstance()方法中的methodToHandler
  //key为接口中的方法,value为SynchronousMethodHandler和DefaultMethodHandler类型
  //所以接下来就去看这两个类型的invoke方法
  return dispatch.get(method).invoke(args);
}
DefaultMethodHandler的invoke()
public Object invoke(Object[] argv) throws Throwable {
  if (handle == null) {
    throw new IllegalStateException(
        "Default method handler invoked before proxy has been bound.");
  }
  //default修饰的方法就直接执行
  return handle.invokeWithArguments(argv);
}
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);
      } 
      //......
    }
  }
}

#SynchronousMethodHandler
Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {
  //调用RequestInterceptor,根据template生成Request对象
  Request request = targetRequest(template);
  //......
  //响应对象
  Response response;
  long start = System.nanoTime();
  try {
    //调用客户端的execute执行请求
    response = client.execute(request, options);
  } catch (IOException e) {
    //......
  }
  long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
  boolean shouldClose = true;
  try {
    //......
    //对response进行解码
    if (Response.class == metadata.returnType()) {
      if (response.body() == null) {
        return response;
      }
      if (response.body().length() == null ||
          response.body().length() > MAX_RESPONSE_BUFFER_SIZE) {
        shouldClose = false;
        return response;
      }
      byte[] bodyData = Util.toByteArray(response.body().asInputStream());
      return response.toBuilder().body(bodyData).build();
    }
    if (response.status() >= 200 && response.status() < 300) {
      if (void.class == metadata.returnType()) {
        return null;
      } else {
        Object result = decode(response);
        shouldClose = closeAfterDecode;
        return result;
      }
    } else if (decode404 && response.status() == 404 && void.class != metadata.returnType()) {
      Object result = decode(response);
      shouldClose = closeAfterDecode;
      return result;
    } else {
      throw errorDecoder.decode(metadata.configKey(), response);
    }
  }
  //......
}

真正执行请求的client.execute(request, options)是一个接口方法,是由不同的客户端工具进行实现。如果没有导入Ribbon,那么就用feign自带的Client.Default内部进行实现。Client是一个接口。

#Client.Default
public Response execute(Request request, Options options) throws IOException {
  //convertAndSend()发送请求
  HttpURLConnection connection = convertAndSend(request, options);
  //convertResponse()响应解码
  return convertResponse(connection, request);
}

如果导入了Ribbon,那么就是LoadBalancerFeignClient实现,内部使用Ribbon进行负载均衡

#LoadBalancerFeignClient
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);
		FeignLoadBalancer.RibbonRequest ribbonRequest = new FeignLoadBalancer.RibbonRequest(
				this.delegate, request, uriWithoutHost);
		IClientConfig requestConfig = getClientConfig(options, clientName);
		return lbClient(clientName)
				.executeWithLoadBalancer(ribbonRequest, requestConfig).toResponse();
	}
	//......
}

到这里,没有导入Hystrix创建代理对象的流程就分析完了,一些具体解析的方法并没有去详细分析,因为我们主要是理解openfeign的执行流程,所以分析创建代理对象,然后到真正执行请求的地方就行了。接下来是去分析引入了Hystrix后是如何创建代理。

HystrixTargeter创建代理对象
#HystrixTargeter
public  T target(FeignClientFactoryBean factory, Feign.Builder feign,
		FeignContext context, Target.HardCodedTarget target) {
    //判断是否为HystrixFeign类型
	if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) {
        //这里会调用ReflectiveFeign的那段逻辑
		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) {
		return targetWithFallback(name, context, target, builder, fallback);
	}
	Class fallbackFactory = factory.getFallbackFactory();
	if (fallbackFactory != void.class) {
		return targetWithFallbackFactory(name, context, target, builder,
				fallbackFactory);
	}
    //执行到这说明没有设置降级,又会回到ReflectiveFeign
	return feign.target(target);
}

虽然导入了Hystrix,但是内部还是会判断是否设置过降级,如果没有,会回到普通的调用链路。上面的降级分支最终都会合并到一起,所以分析一个方法就行。

#HystrixTargeter
private  T targetWithFallback(String feignClientName, FeignContext context,
		Target.HardCodedTarget target, HystrixFeign.Builder builder,
		Class fallback) {
	T fallbackInstance = getFromContext("fallback", feignClientName, context,
			fallback, target.type());
    //创建代理对象,跟进去
	return builder.target(target, fallbackInstance);
}

#HystrixFeign.Builder
public  T target(Target target, T fallback) {
  //newInstance会回到ReflectiveFeign逻辑,我们关心的是引入hystrix后,InvocationHandler的类型
  //在build中会设置InvocationHandlerFactory的类型
  return build(fallback != null ? new FallbackFactory.Default(fallback) : null)
      .newInstance(target);
}

#HystrixFeign.Builder
Feign build(final FallbackFactory nullableFallbackFactory) {
  super.invocationHandlerFactory(new InvocationHandlerFactory() {
    @Override
    public InvocationHandler create(Target target,
                                    Map dispatch) {
      //最终返回了HystrixInvocationHandler实例,所以去看它的invoke方法
      return new HystrixInvocationHandler(target, dispatch, setterFactory,
          nullableFallbackFactory);
    }
  });
  super.contract(new HystrixDelegatingContract(contract));
  return super.build();
}

#HystrixInvocationHandler
public Object invoke(final Object proxy, final Method method, final Object[] args)
    throws Throwable {
  //......
  HystrixCommand hystrixCommand =
      new HystrixCommand(setterMethodMap.get(method)){
      	@Override
		protected Object run() throws Exception {
		  try {
            //在这里回到SynchronousMethodHandler和DefaultMethodHandler的invoke逻辑
		    return HystrixInvocationHandler.this.dispatch.get(method).invoke(args);
		  } catch (Exception e) {
		    throw e;
		  } catch (Throwable t) {
		    throw (Error) t;
		  }
		}	
      //......
  };
  //最终调用到Hystrix处理逻辑
  return hystrixCommand.execute();
}
 

到这里Hystrix的代理逻辑也分析完了,它和默认创建代理对象的逻辑就是invoke()的实现不同,它只是对请求加了熔断降级的处理,其他的流程基本一致。

以上就是openfeign源码分析的整体流程,首先从feign的功能是如何开启的开始分析,然后到FeignClient是如何添加到容器当中,接着分析FeignClient是如何被代理创建,最后分析了默认方式和引入Hystrix的方式分别是如何执行的。总的来说,如果只是理解openfeign的大概执行流程,了解这么多已经足够了,但还想知道一些对象具体是如何解析创建出来、请求响应是如何执行的,那请大家自行研究。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5659384.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-16
下一篇 2022-12-16

发表评论

登录后才能评论

评论列表(0条)