深入分析Feign的启动流程

深入分析Feign的启动流程

基于openfeign2.0.0

在springBoot中,在启动类上加上@EnableFeignClients注解就可以使用Feign了,那么其中的原理是什么呢?下面让我们一起探索。

@EnableFeignClients

我们从@EnableFeignClients注解开始进行剖析:先看代码

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
  ...//省略

可以看到导入了FeignClientsRegistrar.class这个注册类,那么我们重点关注FeignClientsRegistrar里面究竟做了什么。

FeignClientsRegistrar

在这里插入图片描述
FeignClientsRegistrar继承了ImportBeanDefinitionRegistrarImportBeanDefinitionRegistrar是spring注册BeanDefinition的注册器,属于FactoryBeanPostProcessor,在启动过程中会调用registerBeanDefinitions()方法

//org.springframework.cloud.openfeign.FeignClientsRegistrar#registerBeanDefinitions

@Override
	public void registerBeanDefinitions(AnnotationMetadata metadata,
			BeanDefinitionRegistry registry) {
		//创建默认子上下文
		registerDefaultConfiguration(metadata, registry);
		//扫描@FeignClient注解并生成代理对象
		registerFeignClients(metadata, registry);
	}

先看FeignClientsRegistrar#registerDefaultConfiguration,后面还有具体分析

//org.springframework.cloud.openfeign.FeignClientsRegistrar#registerDefaultConfiguration

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();
			}
			//如果在@EnableFeignClients注解上加入了`defaultConfiguration`属性,就会使用指定的配置
			registerClientConfiguration(registry, name,
					defaultAttrs.get("defaultConfiguration"));
		}
	}

如果在@EnableFeignClients注解上加入了defaultConfiguration属性,就会使用这个配置生成springBoot容器子上下文,name是以default.开头
继续看下一个方法FeignClientsRegistrar#registerFeignClients

//org.springframework.cloud.openfeign.FeignClientsRegistrar#registerFeignClients

public void registerFeignClients(AnnotationMetadata metadata,
			BeanDefinitionRegistry registry) {
			//获取ClassPathScanningCandidateComponentProvider
		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");
		//如果没有指定clients属性,那么就扫描所有指定包下@FeignClient的类
		//没有指定则取@EnableFeignClients所在包下路径
		if (clients == null || clients.length == 0) {
			scanner.addIncludeFilter(annotationTypeFilter);
			basePackages = getBasePackages(metadata);
		}
		//只扫描指定的FeignClient
		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) {
					// 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);
					//如果@FeignClient指定了configuration,创建Spring容器子上下文
					registerClientConfiguration(registry, name,
							attributes.get("configuration"));
					//注册Feign的代理类
					registerFeignClient(registry, annotationMetadata, attributes);
				}
			}
		}
	}

大致做了这几件事

  • 解析注解上的信息,根据注解的信息做相应的事情
  • 调用registerFeignClient注册Feign代理类
    下面我们【重点】关注两个方法registerClientConfigurationregisterFeignClient

FeignClientsRegistrar#registerClientConfiguration

//org.springframework.cloud.openfeign.FeignClientsRegistrar#registerClientConfiguration

private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name,
			Object configuration) {
		BeanDefinitionBuilder builder = BeanDefinitionBuilder
				.genericBeanDefinition(FeignClientSpecification.class);
		//设置FeignClientSpecification构造器需要的参数
		builder.addConstructorArgValue(name);
		builder.addConstructorArgValue(configuration);
		registry.registerBeanDefinition(
				name + "." + FeignClientSpecification.class.getSimpleName(),
				builder.getBeanDefinition());
	}

会注册一个FeignClientSpecification的类,并且名称是@FeignClient中的name或者value

//org.springframework.cloud.openfeign.FeignClientSpecification

class FeignClientSpecification implements NamedContextFactory.Specification {

	private String name;

	private Class<?>[] configuration;

	public FeignClientSpecification() {}
	//。。。略
}

继承了NamedContextFactory的内部类Specification
再看一下NamedContextFactory类型

NamedContextFactory

这个类是微服务的上下文,在这里如果理解spring的父子上下文会更容易理解这种设计思想,进行了容器的隔离,类似于类加载器的双亲委派机制
它的功能主要是

  • 创建AnnotationConfigApplication子上下文
  • 在上下文中创建并获取bean实例
  • 当上下文销毁时清除其中的feign实例
//org.springframework.cloud.context.named.NamedContextFactory

public abstract class NamedContextFactory<C extends NamedContextFactory.Specification>
		implements DisposableBean, ApplicationContextAware {

	private final String propertySourceName;

	private final String propertyName;

	private Map<String, AnnotationConfigApplicationContext> contexts = new ConcurrentHashMap<>();

	private Map<String, C> configurations = new ConcurrentHashMap<>();

	private ApplicationContext parent;

	private Class<?> defaultConfigType;
    //...略
    
    @Override
	public void setApplicationContext(ApplicationContext parent) throws BeansException {
		this.parent = parent;
	}
	
    @Override
	public void destroy() {
		Collection<AnnotationConfigApplicationContext> values = this.contexts.values();
		for (AnnotationConfigApplicationContext context : values) {
			// This can fail, but it never throws an exception (you see stack traces
			// logged as WARN).
			context.close();
		}
		this.contexts.clear();
	}
}

可以看出NamedContextFactory只处理NamedContextFactory.Specification类型,而上面提到的FeignClientSpecification就是这个类型,那么这个是什么时候创建的呢?

FeignAutoConfiguration

在这里插入图片描述
springBoot的一大亮点就是自动装配,会自动加载模块下的META-INF/spring.factories,那么FeignAutoConfiguration类就会被加载。那么我们关注内部重要代码。

//org.springframework.cloud.openfeign.FeignAutoConfiguration

@Configuration
@ConditionalOnClass(Feign.class)
@EnableConfigurationProperties({FeignClientProperties.class, FeignHttpClientProperties.class})
public class FeignAutoConfiguration {

	@Autowired(required = false)
	private List<FeignClientSpecification> configurations = new ArrayList<>();

	@Bean
	public HasFeatures feignFeature() {
		return HasFeatures.namedFeature("Feign", Feign.class);
	}

	//FeignContext 是NamedContextFactory的实现,这个方法返回Feign的上下文
	@Bean
	public FeignContext feignContext() {
		FeignContext context = new FeignContext();
		context.setConfigurations(this.configurations);
		return context;
	}

    //如果开启了熔断,那么返回HystrixTargeter
	@Configuration
	@ConditionalOnClass(name = "feign.hystrix.HystrixFeign")
	protected static class HystrixFeignTargeterConfiguration {
		@Bean
		@ConditionalOnMissingBean
		public Targeter feignTargeter() {
			return new HystrixTargeter();
		}
	}
	//如果没有开启熔断,那么返回DefaultTargeter
	@Configuration
	@ConditionalOnMissingClass("feign.hystrix.HystrixFeign")
	protected static class DefaultFeignTargeterConfiguration {
		@Bean
		@ConditionalOnMissingBean
		public Targeter feignTargeter() {
			return new DefaultTargeter();
		}
	}
	//...略

FeignContext

FeignContext继承了NamedContextFactory

//org.springframework.cloud.openfeign.FeignContext

public class FeignContext extends NamedContextFactory<FeignClientSpecification> {

	public FeignContext() {
		super(FeignClientsConfiguration.class, "feign", "feign.client.name");
	}
}

FeignContext向父类传入了FeignClientsConfiguration.class,稍微看下里面是什么

//org.springframework.cloud.openfeign.FeignClientsConfiguration

@Configuration
public class FeignClientsConfiguration {

	@Autowired
	private ObjectFactory<HttpMessageConverters> messageConverters;

	@Autowired(required = false)
	private List<AnnotatedParameterProcessor> parameterProcessors = new ArrayList<>();

	@Autowired(required = false)
	private List<FeignFormatterRegistrar> feignFormatterRegistrars = new ArrayList<>();

	@Autowired(required = false)
	private Logger logger;

	@Bean
	@ConditionalOnMissingBean
	public Decoder feignDecoder() {
		return new ResponseEntityDecoder(new SpringDecoder(this.messageConverters));
	}

	@Bean
	@ConditionalOnMissingBean
	public Encoder feignEncoder() {
		return new SpringEncoder(this.messageConverters);
	}

	@Bean
	@ConditionalOnMissingBean
	public Contract feignContract(ConversionService feignConversionService) {
		return new SpringMvcContract(this.parameterProcessors, feignConversionService);
	}

	@Bean
	public FormattingConversionService feignConversionService() {
		FormattingConversionService conversionService = new DefaultFormattingConversionService();
		for (FeignFormatterRegistrar feignFormatterRegistrar : feignFormatterRegistrars) {
			feignFormatterRegistrar.registerFormatters(conversionService);
		}
		return conversionService;
	}

	@Configuration
	@ConditionalOnClass({ HystrixCommand.class, HystrixFeign.class })
	protected static class HystrixFeignConfiguration {
		@Bean
		@Scope("prototype")
		@ConditionalOnMissingBean
		//配置文件中feign.hystrix.enabled=true
		@ConditionalOnProperty(name = "feign.hystrix.enabled", matchIfMissing = false)
		public Feign.Builder feignHystrixBuilder() {
			return HystrixFeign.builder();
		}
	}

	@Bean
	@ConditionalOnMissingBean
	public Retryer feignRetryer() {
		return Retryer.NEVER_RETRY;
	}

	@Bean
	@Scope("prototype")
	@ConditionalOnMissingBean
	public Feign.Builder feignBuilder(Retryer retryer) {
		return Feign.builder().retryer(retryer);
	}

	@Bean
	@ConditionalOnMissingBean(FeignLoggerFactory.class)
	public FeignLoggerFactory feignLoggerFactory() {
		return new DefaultFeignLoggerFactory(logger);
	}
}

就是配置Feign需要的各种属性:重试策略、超时策略、日志配置、编解码,Contract等配置

FeignClientsRegistrar#registerFeignClient

让我们回到最开始的FeignClientsRegistrar中,上面提到重点关注的最后一个方法registerFeignClient

//org.springframework.cloud.openfeign.FeignClientsRegistrar#registerFeignClient

private void registerFeignClient(BeanDefinitionRegistry registry,
			AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
		String className = annotationMetadata.getClassName();
		//【关注】FeignClientFactoryBean,生产FeignClient的代理对象
		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);
		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 = 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;
		}

		BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,
				new String[] { alias });
		BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
	}

FeignClientFactoryBean#getObject

来到生产FeignClient的FactoryBean类中
只关注getObject方法

//org.springframework.cloud.openfeign.FeignClientFactoryBean#getObject

class FeignClientFactoryBean
		implements FactoryBean<Object>, InitializingBean, ApplicationContextAware {
		//...
	@Override
		public Object getObject() throws Exception {
			return getTarget();
		}
		//...
}

调用的是getTarget

//org.springframework.cloud.openfeign.FeignClientFactoryBean#getTarget

<T> T getTarget() {
    //获取上面已经创建的Feign上下文对象
		FeignContext context = this.applicationContext.getBean(FeignContext.class);
		//从FeignContext中拿到buider对象,如果没有服务名称对应的FeignContext,则此时创建对应的上下文
		//生成buider对象,来生成对应的Feign,其内设置了Feign的属性,如指定的超时策略,重试策略,拦截器等。。
		Feign.Builder builder = feign(context);
     //如果注解的url为空,则选择负载均衡
		if (!StringUtils.hasText(this.url)) {
			if (!this.name.startsWith("http")) {
				this.url = "http://" + this.name;
			}
			else {
				this.url = this.name;
			}
			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")) {
			this.url = "http://" + this.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();
			}
			builder.client(client);
		}
		Targeter targeter = get(context, Targeter.class);
		//生成默认的代理类,这里获取的target是`FeignAutoConfiguration`中产生的
		return (T) targeter.target(this, builder, context,
				new HardCodedTarget<>(this.type, this.name, url));
	}

下面分析一些重要的方法

feign

//org.springframework.cloud.openfeign.FeignClientFactoryBean#feign

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

		configureFeign(context, builder);

		return builder;
	}

在这里大量的使用到了get()方法,我们只关注需要的,调用栈就一笔带过
FeignClientFactoryBean#get–>NamedContextFactory#getInstance(java.lang.String, java.lang.Class<T>)–>NamedContextFactory#getContext

//org.springframework.cloud.context.named.NamedContextFactory#getContext

protected AnnotationConfigApplicationContext getContext(String name) {
		if (!this.contexts.containsKey(name)) {
			synchronized (this.contexts) {
				if (!this.contexts.containsKey(name)) {
				//如果根据服务名称无法获取对应的上下文,则创建
					this.contexts.put(name, createContext(name));
				}
			}
		}
		return this.contexts.get(name);
	}

contexts 对应

private Map<String, AnnotationConfigApplicationContext> contexts = new ConcurrentHashMap<>();

如果根据服务名称无法获取对应的上下文,则创建AnnotationConfigApplicationContext上下文

createContext创建上下文

configurations上文有稍微出现过,这个Map的value是上文提到的NamedContextFactory.Specification,它的实现类是FeignClientSpecification
RibbonClientSpecification,这个实现类是整合了ribbon情况的存在。

//org.springframework.cloud.context.named.NamedContextFactory#createContext
	   ...
private Map<String, C> configurations = new ConcurrentHashMap<>();
       ...
protected AnnotationConfigApplicationContext createContext(String name) {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
		//如果Map中包含对应的实例,则注册到上下文中
		if (this.configurations.containsKey(name)) {
			for (Class<?> configuration : this.configurations.get(name)
					.getConfiguration()) {
				context.register(configuration);
			}
		}
		//循环所有的上下文,以default.开始的,这个在FeignClientsRegistrar中已经说明过
		for (Map.Entry<String, C> entry : this.configurations.entrySet()) {
			if (entry.getKey().startsWith("default.")) {
				for (Class<?> configuration : entry.getValue().getConfiguration()) {
					context.register(configuration);
				}
			}
		}
		context.register(PropertyPlaceholderAutoConfiguration.class,
				this.defaultConfigType);
		context.getEnvironment().getPropertySources().addFirst(new MapPropertySource(
				this.propertySourceName,
				Collections.<String, Object>singletonMap(this.propertyName, name)));
		//设置父上下文
		if (this.parent != null) {
			// Uses Environment from parent as well as beans
			context.setParent(this.parent);
			// jdk11 issue
			// https://github.com/spring-cloud/spring-cloud-netflix/issues/3101
			context.setClassLoader(this.parent.getClassLoader());
		}
		context.setDisplayName(generateDisplayName(name));
		//spring容器刷新
		context.refresh();
		return context;
	}

好了,这里上下文的问题也解决了,我们回到FeignClientFactoryBean#loadBalance

loadBanlance

如果@FeignClient没有注解没有指定url

//org.springframework.cloud.openfeign.FeignClientFactoryBean#loadBalance

protected <T> T loadBalance(Feign.Builder builder, FeignContext context,
			HardCodedTarget<T> target) {
			//在FeignContext上下文中获取Client
		Client client = getOptional(context, Client.class);
		if (client != null) {
			builder.client(client);
			//从上下文中获取Targeter 对象,如果是开启了熔断的就是HystrixTargeter ,否则是DefaultTarget
			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?");
	}

HystrixTargeter #target

//org.springframework.cloud.openfeign.HystrixTargeter#target

@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;
		SetterFactory setterFactory = getOptional(factory.getName(), context,
				SetterFactory.class);
		//理解中...
		if (setterFactory != null) {
			builder.setterFactory(setterFactory);
		}
		//设置单独的回调方法
		Class<?> fallback = factory.getFallback();
		if (fallback != void.class) {
			return targetWithFallback(factory.getName(), context, target, builder,
					fallback);
		}
		//设置熔断回调工厂
		Class<?> fallbackFactory = factory.getFallbackFactory();
		if (fallbackFactory != void.class) {
			return targetWithFallbackFactory(factory.getName(), context, target, builder,
					fallbackFactory);
		}

		return feign.target(target);
	}

无论是返回哪个方法,如果打开了熔断器最终都会调用到HystrixFeignr#build(),然后得到返回的ReflectiveFeign调用newInstance方法

build

//feign.hystrix.HystrixFeign.Builder#build(feign.hystrix.FallbackFactory<?>)

Feign build(final FallbackFactory<?> nullableFallbackFactory) {
	//传入匿名内部类InvocationHandlerFactory,重写create方法创建HystrixInvocationHandler
      super.invocationHandlerFactory(new InvocationHandlerFactory() {
        @Override
        public InvocationHandler create(Target target,
                                        Map<Method, MethodHandler> dispatch) {
          return new HystrixInvocationHandler(target, dispatch, setterFactory,
              nullableFallbackFactory);
        }
      });
      //传入contract的静态代理HystrixDelegatingContract
      super.contract(new HystrixDelegatingContract(contract));
      //返回ReflectiveFeign,内部持有上面创建的匿名内部类InvocationHandlerFactory
      return super.build();
    }
  • 重写了InvocationHandlerFactory的create方法,创建HystrixInvocationHandler
  • 代理了Contract,处理返回类型
  • 返回ReflectiveFeign,调用下面的newInstance方法

newInstance

//feign.ReflectiveFeign#newInstance

@Override
  public <T> T newInstance(Target<T> target) {
  //获取所有的MethodHandler,每一个对应处理我们写的feign接口
  //里面使用的contract是在FeignClientFactoryBean#feign中设置的SpringMvcContract
  //SpringMvcContract这个类在FeignAutoConfiguration中创建的
    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);
        //target方法和拦截的方法DefaultMethodHandler对应起来
        methodToHandler.put(method, handler);
      } else {
      //target方法和拦截的方法SynchronousMethodHandler对应起来
        methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
      }
    }
    //获取JDK代理的InvocationHandler 实现FeignInvocationHandler
    InvocationHandler handler = factory.create(target, methodToHandler);
    //创建Feign代理对象
    T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
        new Class<?>[] {target.type()}, handler);

    for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
    	//默认方法绑定代理对象
      defaultMethodHandler.bindTo(proxy);
    }
    //返回生成的feign代理对象
    return proxy;
  }

targetToHandlersByName#apply

这个方法使用SpringMvcContract去解析@RequestMapping的注解,取得配置信息

//feign.ReflectiveFeign.ParseHandlersByName#apply

public Map<String, MethodHandler> apply(Target key) {
	//contract为SpringMvcContract,解析@RequestMapping注解信息,获取对应的方法数据
      List<MethodMetadata> metadata = contract.parseAndValidatateMetadata(key.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);
        } else if (md.bodyIndex() != null) {
          buildTemplate = new BuildEncodedTemplateFromArgs(md, encoder, queryMapEncoder);
        } else {
          buildTemplate = new BuildTemplateByResolvingArgs(md, queryMapEncoder);
        }
        //将所有的feignClient名称和MethodHandler对应起来
        //factory是SynchronousMethodHandler$Factory,factory#create方法里创建SynchronousMethodHandler
        result.put(md.configKey(),
            factory.create(key, md, buildTemplate, options, decoder, errorDecoder));
      }
      return result;
    }
  • contract是使用SpringMvcContract,所以可以解析@RequestMapping注解。如果是熔断的还会使用HystrixDelegatingContract静态代理SpringMvcContract,处理返回值
  • 如果是使用默认的Contract.Default,那么接只能使用@RequestLine、@Headers等原生注解
  • 使用Map将FeignClient的方法名称和SynchronousMethodHandler一一映射起来

create

这个factory是InvocationHandlerFactory,是之前在build()方法中创建的匿名内部类,返回HystrixInvocationHandler

//feign.hystrix.HystrixFeign.Builder#build(feign.hystrix.FallbackFactory<?>)

super.invocationHandlerFactory(new InvocationHandlerFactory() {
        @Override
        public InvocationHandler create(Target target,
                                        Map<Method, MethodHandler> dispatch) {
          return new HystrixInvocationHandler(target, dispatch, setterFactory,
              nullableFallbackFactory);
        }
      });

至此,FeignClientFactoryBean#getObject返回feign的动态代理对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值