深入分析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继承了ImportBeanDefinitionRegistrar
,ImportBeanDefinitionRegistrar
是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代理类
下面我们【重点
】关注两个方法registerClientConfiguration、registerFeignClient
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的动态代理对象。