Feign 源码分析
Feign内部实现原理是基于restTemplate,而restTemplate是基于httpClient,他可以整ribbon、hystric etc 在springcloud使用篇我做了详细的介绍
源码分析
开启注解扫描,分析他是如何与spring整合
EnableFeignClients({“xxx.xxxx.xxx”})
FeignClientsRegistrar 导入该类到spring容器中。前面我们在spring源码分析中,已经对Import进行源码分析。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
在分析FeignClientsRegistrar 该类之前我们先分析以下几个类
- ImportBeanDefinitionRegistrar 在导入该类的时候初始化完成的时候回回调该方法registerBeanDefinitions 这也是spring扩展的地方
- ResourceLoaderAware 设置当前上下文的加载器
- EnvironmentAware 环境加载
org.springframework.cloud.openfeign.FeignClientsRegistrar#registerBeanDefinitions
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
// 注册默认配置
registerDefaultConfiguration(metadata, registry);
// 扫描所有feignClient注解
registerFeignClients(metadata, registry);
}
org.springframework.cloud.openfeign.FeignClientsRegistrar#registerDefaultConfiguration
private void registerDefaultConfiguration(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
// 通feign的名字获取到所有使用EnableFeignClients 的注解
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"));
}
}
org.springframework.cloud.openfeign.FeignClientsRegistrar#registerClientConfiguration 通过下面类注册到spring容器中,接续分析
private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name,
Object configuration) {
// 加载FeignClientSpecification bean
// 构建builer
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(FeignClientSpecification.class);
// 设置到构造函数
builder.addConstructorArgValue(name);
// 添加构造参数
builder.addConstructorArgValue(configuration);
// 注册bean
registry.registerBeanDefinition(
name + "." + FeignClientSpecification.class.getSimpleName(),
builder.getBeanDefinition());
}
org.springframework.cloud.openfeign.FeignClientsRegistrar#registerFeignClients
public void registerFeignClients(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
// 加载ClassPath下面的类
ClassPathScanningCandidateComponentProvider scanner = getScanner();
scanner.setResourceLoader(this.resourceLoader);
Set<String> basePackages;
// 获取到EnableFeignClients的属性
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);
// 确定扫描的包路径列表
basePackages = getBasePackages(metadata);
}
else {
//如果设置了,最终扫出来的Bean必须是注解中设置的那些
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();
//必须注解在interface上
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"));
registerFeignClient(registry, annotationMetadata, attributes);
}
}
}
}
org.springframework.cloud.openfeign.FeignClientsRegistrar#registerFeignClient
private void registerFeignClient(BeanDefinitionRegistry registry,
AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
String className = annotationMetadata.getClassName();
BeanDefinitionBuilder definition = BeanDefinitionBuilder
.genericBeanDefinition(FeignClientFactoryBean.class);
validate(attributes);
//将属性设置到FeignClientFactoryBean 中
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"));
//设置Autowire 类型
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;
}
//注册bean
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,
new String[] { alias });
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
}
另一个往Registry里面添加的BeanDefinition则是FeignClientFactoryBean,负责注册FeignClient.
也就是说,feign的注册一共分为以下几步。
FeignClientFactoryBean,他是一个工厂类,Spring Context创建bean会调用getObject方法
org.springframework.cloud.openfeign.FeignClientFactoryBean#getObject
public Object getObject() throws Exception {
return getTarget();
}
org.springframework.cloud.openfeign.FeignClientFactoryBean#getTarget
<T> T getTarget() {
FeignContext context = applicationContext.getBean(FeignContext.class);
//获取一个默认的builder
Feign.Builder builder = feign(context);
if (!StringUtils.hasText(this.url)) {
//如果没有指定url,获取name值拼接默认url
String url;
if (!this.name.startsWith("http")) {
url = "http://" + this.name;
}
else {
url = this.name;
}
url += cleanPath();
return (T) loadBalance(builder, context, new HardCodedTarget<>(this.type,
this.name, url));
}
if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {
this.url = "http://" + this.url;
}
String url = this.url + cleanPath();
Client client = getOptional(context, Client.class);
if (client != null) {
if (client instanceof LoadBalancerFeignClient) {
//使用ribbon提供的负载均衡
// 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);
return (T) targeter.target(this, builder, context, new HardCodedTarget<>(
this.type, this.name, url));
}
总结: 如果指定URL,没有指定Client就使用URL,相当于直连,没有负载均衡。指定了client,可以使用负载均衡。默认版本开启负载均衡。
org.springframework.cloud.openfeign.FeignClientFactoryBean#feign
protected Feign.Builder feign(FeignContext context) {
//获取FeignClientsConfiguration 中注册的bean ,设置到feign中
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;
}
编码器、解码器等等在哪里初始化呢》。。。。 等等。
@Bean
@ConditionalOnMissingBean
public Decoder feignDecoder() {
return new OptionalDecoder(new ResponseEntityDecoder(new SpringDecoder(this.messageConverters)));
}
@Bean
@ConditionalOnMissingBean
public Encoder feignEncoder() {
return new SpringEncoder(this.messageConverters);
}
org.springframework.cloud.openfeign.FeignClientFactoryBean#configureFeign
protected void configureFeign(FeignContext context, Feign.Builder builder) {
//获取.properties的属性
FeignClientProperties properties = applicationContext.getBean(FeignClientProperties.class);
if (properties != null) {
if (properties.isDefaultToProperties()) {
//默认为true
configureUsingConfiguration(context, builder);
configureUsingProperties(properties.getConfig().get(properties.getDefaultConfig()), builder);
configureUsingProperties(properties.getConfig().get(this.name), builder);
} else {
configureUsingProperties(properties.getConfig().get(properties.getDefaultConfig()), builder);
configureUsingProperties(properties.getConfig().get(this.name), builder);
configureUsingConfiguration(context, builder);
}
} else {
configureUsingConfiguration(context, builder);
}
}
用户自定义
org.springframework.cloud.openfeign.FeignClientFactoryBean#configureUsingConfiguration
//获取用户通过configuration @Bean的自定义配置
protected void configureUsingConfiguration(FeignContext context, Feign.Builder builder) {
Logger.Level level = getOptional(context, Logger.Level.class);
if (level != null) {
builder.logLevel(level);
}
Retryer retryer = getOptional(context, Retryer.class);
if (retryer != null) {
builder.retryer(retryer);
}
ErrorDecoder errorDecoder = getOptional(context, ErrorDecoder.class);
if (errorDecoder != null) {
builder.errorDecoder(errorDecoder);
}
//connectTimeoutMillis和readTimeoutMillis的默认值
Request.Options options = getOptional(context, Request.Options.class);
if (options != null) {
builder.options(options);
}
Map<String, RequestInterceptor> requestInterceptors = context.getInstances(
this.name, RequestInterceptor.class);
if (requestInterceptors != null) {
builder.requestInterceptors(requestInterceptors.values());
}
if (decode404) {
builder.decode404();
}
}
配置文件读取
protected void configureUsingProperties(FeignClientProperties.FeignClientConfiguration config, Feign.Builder builder) {
if (config == null) {
return;
}
if (config.getLoggerLevel() != null) {
builder.logLevel(config.getLoggerLevel());
}
//设置connectTimeoutMillis和readTimeoutMillis的值,这里的属性值来自于.properties配置的
if (config.getConnectTimeout() != null && config.getReadTimeout() != null) {
builder.options(new Request.Options(config.getConnectTimeout(), config.getReadTimeout()));
}
if (config.getRetryer() != null) {
Retryer retryer = getOrInstantiate(config.getRetryer());
builder.retryer(retryer);
}
if (config.getErrorDecoder() != null) {
ErrorDecoder errorDecoder = getOrInstantiate(config.getErrorDecoder());
builder.errorDecoder(errorDecoder);
}
if (config.getRequestInterceptors() != null && !config.getRequestInterceptors().isEmpty()) {
// this will add request interceptor to builder, not replace existing
for (Class<RequestInterceptor> bean : config.getRequestInterceptors()) {
RequestInterceptor interceptor = getOrInstantiate(bean);
builder.requestInterceptor(interceptor);
}
}
if (config.getDecode404() != null) {
if (config.getDecode404()) {
builder.decode404();
}
}
if (Objects.nonNull(config.getEncoder())) {
builder.encoder(getOrInstantiate(config.getEncoder()));
}
if (Objects.nonNull(config.getDecoder())) {
builder.decoder(getOrInstantiate(config.getDecoder()));
}
if (Objects.nonNull(config.getContract())) {
builder.contract(getOrInstantiate(config.getContract()));
}
}
把配置文件中的配置项初始化到FeignClientProperties中
- 如果配置文件中没有配置,则将FeignClientsConfiguration中的bean作为默认值设置到builder.
- 如果配置问你安中有配置,并且用默认加载顺序时,首先加载FeignClientsConfiguration中的bean,然后加载在注解中配置configuration, 最后加载配置文件中的。
- 如果不是默认加载顺序,则首先加载注解中配置configuration,然后在从配置文件中配置,最后加载FeignClientsConfiguration中的配置。
如何生成代理对象…
org.springframework.cloud.openfeign.FeignClientFactoryBean#loadBalance
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?");
}
org.springframework.cloud.openfeign.HystrixTargeter
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);
}
如果配置开启容错,则会采用默认
条件装配
org.springframework.cloud.openfeign.FeignAutoConfiguration.HystrixFeignTargeterConfiguration
@Configuration
@ConditionalOnClass(name = "feign.hystrix.HystrixFeign")
protected static class HystrixFeignTargeterConfiguration {
@Bean
@ConditionalOnMissingBean
public Targeter feignTargeter() {
return new HystrixTargeter();
}
}
@Configuration
@ConditionalOnMissingClass("feign.hystrix.HystrixFeign")
protected static class DefaultFeignTargeterConfiguration {
@Bean
@ConditionalOnMissingBean
public Targeter feignTargeter() {
return new DefaultTargeter();
}
}
默认。。。。。
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context,
Target.HardCodedTarget<T> target) {
return feign.target(target);
}
Feign 如何。。。。。。使用
public <T> T target(Target<T> target) {
return this.build().newInstance(target);
}
feign.ReflectiveFeign#newInstance
public <T> T newInstance(Target<T> target) {
// 为每一个方法创建一个SynchronousMethodHandler对象,并放到map中
Map<String, MethodHandler> nameToHandler = this.targetToHandlersByName.apply(target);
Map<Method, MethodHandler> methodToHandler = new LinkedHashMap();
List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList();
Method[] var5 = target.type().getMethods();
int var6 = var5.length;
for(int var7 = 0; var7 < var6; ++var7) {
Method method = var5[var7];
if (method.getDeclaringClass() != Object.class) {
if (Util.isDefault(method)) {
// DefaultHandler
DefaultMethodHandler handler = new DefaultMethodHandler(method);
defaultMethodHandlers.add(handler);
methodToHandler.put(method, handler);
} else {
// SynchronousXXX。。。
methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
}
}
}
InvocationHandler handler = this.factory.create(target, methodToHandler);
T proxy = Proxy.newProxyInstance(target.type().getClassLoader(), new Class[]{target.type()}, handler);
Iterator var12 = defaultMethodHandlers.iterator();
while(var12.hasNext()) {
DefaultMethodHandler defaultMethodHandler = (DefaultMethodHandler)var12.next();
defaultMethodHandler.bindTo(proxy);
}
return proxy;
}
总结:
- 创建MethodHandler的映射。创建实现类SysnchronousMethodHandler
- 通过InvacationHandlerFactory创建InvocationHandler
- 绑定接口的default方法。通过DefaultMethodHandler绑定
feign.ReflectiveFeign.ParseHandlersByName#apply
public Map<String, MethodHandler> apply(Target key) {
List<MethodMetadata> metadata = this.contract.parseAndValidatateMetadata(key.type());
Map<String, MethodHandler> result = new LinkedHashMap();
MethodMetadata md;
Object buildTemplate;
for(Iterator var4 = metadata.iterator(); var4.hasNext(); result.put(md.configKey(), this.factory.create(key, md, (Factory)buildTemplate, this.options, this.decoder, this.errorDecoder))) {
md = (MethodMetadata)var4.next();
if (!md.formParams().isEmpty() && md.template().bodyTemplate() == null) {
buildTemplate = new ReflectiveFeign.BuildFormEncodedTemplateFromArgs(md, this.encoder, this.queryMapEncoder);
} else if (md.bodyIndex() != null) {
buildTemplate = new ReflectiveFeign.BuildEncodedTemplateFromArgs(md, this.encoder, this.queryMapEncoder);
} else {
buildTemplate = new ReflectiveFeign.BuildTemplateByResolvingArgs(md, this.queryMapEncoder);
}
}
return result;
}
feign.SynchronousMethodHandler.Factory#create
public MethodHandler create(Target<?> target, MethodMetadata md, feign.RequestTemplate.Factory buildTemplateFromArgs, Options options, Decoder decoder, ErrorDecoder errorDecoder) {
return new SynchronousMethodHandler(target, this.client, this.retryer, this.requestInterceptors, this.logger, this.logLevel, md, buildTemplateFromArgs, options, decoder, errorDecoder, this.decode404, this.closeAfterDecode);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (!"equals".equals(method.getName())) {
if ("hashCode".equals(method.getName())) {
return this.hashCode();
} else {
return "toString".equals(method.getName()) ? this.toString() : ((MethodHandler)this.dispatch.get(method)).invoke(args);
}
} else {
try {
Object otherHandler = args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;
return this.equals(otherHandler);
} catch (IllegalArgumentException var5) {
return false;
}
}
}
public Object invoke(Object[] argv) throws Throwable {
RequestTemplate template = this.buildTemplateFromArgs.create(argv);
Retryer retryer = this.retryer.clone();
while(true) {
try {
return this.executeAndDecode(template);
} catch (RetryableException var5) {
retryer.continueOrPropagate(var5);
if (this.logLevel != Level.NONE) {
this.logger.logRetry(this.metadata.configKey(), this.logLevel);
}
}
}
}
Object executeAndDecode(RequestTemplate template) throws Throwable {
Request request = this.targetRequest(template);
if (this.logLevel != Level.NONE) {
this.logger.logRequest(this.metadata.configKey(), this.logLevel, request);
}
long start = System.nanoTime();
Response response;
try {
response = this.client.execute(request, this.options);
response.toBuilder().request(request).build();
} catch (IOException var15) {
if (this.logLevel != Level.NONE) {
this.logger.logIOException(this.metadata.configKey(), this.logLevel, var15, this.elapsedTime(start));
}
throw FeignException.errorExecuting(request, var15);
}
long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
boolean shouldClose = true;
Object var10;
try {
if (this.logLevel != Level.NONE) {
response = this.logger.logAndRebufferResponse(this.metadata.configKey(), this.logLevel, response, elapsedTime);
response.toBuilder().request(request).build();
}
if (Response.class == this.metadata.returnType()) {
Response var18;
if (response.body() == null) {
var18 = response;
return var18;
}
if (response.body().length() != null && (long)response.body().length() <= 8192L) {
byte[] bodyData = Util.toByteArray(response.body().asInputStream());
Response var20 = response.toBuilder().body(bodyData).build();
return var20;
}
shouldClose = false;
var18 = response;
return var18;
}
Object result;
if (response.status() >= 200 && response.status() < 300) {
if (Void.TYPE == this.metadata.returnType()) {
result = null;
return result;
}
result = this.decode(response);
shouldClose = this.closeAfterDecode;
var10 = result;
return var10;
}
if (!this.decode404 || response.status() != 404 || Void.TYPE == this.metadata.returnType()) {
throw this.errorDecoder.decode(this.metadata.configKey(), response);
}
result = this.decode(response);
shouldClose = this.closeAfterDecode;
var10 = result;
} catch (IOException var16) {
if (this.logLevel != Level.NONE) {
this.logger.logIOException(this.metadata.configKey(), this.logLevel, var16, elapsedTime);
}
throw FeignException.errorReading(request, response, var16);
} finally {
if (shouldClose) {
Util.ensureClosed(response.body());
}
}
return var10;
}