盘点 Cloud FeignBean 的创建及代理

这是我参与更文挑战的第7天,活动详情查看: 更文挑战

总文档 :文章目录

Github : github.com/black-ant

一 . 前言

前面一篇说了Feign 的初始化配置 , 这一篇来说说 FeingBean 的加载 :

接上一篇中 , FeignClient 被扫描处理 , 加入 Bean 工厂中

BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);

那么后续是如何使用的呢?

二 . FeignBean 的创建

Bean 的创建主要是基于 FeignClientFactoryBean , 通过工厂实现具体的 FeignBean 个体 ,后续接口代理的时候 , 会反射到该类

2.1 发起的原因

  • Step 1 : Spring 加载一个 Bean ,发现 Bean 中有一个 Autowired 标注的对象
  • Step 2 : 通过 AbstractBeanFactory getBean 获取这对象
  • Step 3 : getSingleton 查询到对应的 工厂方法 (FeignClientFactoryBean)
  • Step 4 : 调用 FeignClientFactoryBean # getObject 获取对象
  • Step 5 : ReflectiveFeign 初始化绑定对象 (newInstance)
    • Step 5.1 : ReflectiveFeign.apply(Target target) 对 Method 进行处理
    • Step 5.1 : ReflectiveFeign.apply(Target target) 对 Method 进行处理

简单点说 ,当出现 Autowired 注入 FeginClient 的时候 , 会通过 FeignClientFactoryBean 返回一个代理类

2.2 调用的流程

前置知识点 : FactoryBean 发起 Object 的获取

PS : IOC 容器中会构建 FactoryBean , 在需要实现 Object 的时候 , 调用 FactoryBean 的 getObject 方法获取具体的Object 对象

1
2
3
4
5
6
7
java复制代码C07- FactoryBean
M- T getObject() throws Exception
M- Class<?> getObjectType()
M- default boolean isSingleton()

// PS : 此处 FeignClientFactoryBean 实现了该方法
class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean, ApplicationContextAware

扩展 :
了解过 IOC 流程的应该会比较清楚 , 这里简单点说就是提供一个方法 ,让 IOC 获取 FactoryBean 需要创建的类的实例 (即从 FactoryBean 获取它工厂处理出来的对象)

相关逻辑可以从 DefaultSingletonBeanRegistry # getSingleton 方法中看到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
java复制代码com.gang.cloud.template.demo.client.SampleFeignClient 
-> FeignClientFactoryBean{
type=interface com.gang.cloud.template.demo.client.SampleFeignClient,
name='nacos-account-server',
url='http://nacos-account-server',
path='',
decode404=false,
inheritParentContext=true,
applicationContext=
org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@4eb1c69,
started on Tue May 18 15:47:20 CST 2021,
parent: org.springframework.context.annotation.AnnotationConfigApplicationContext@4cc61eb1,
fallback=void,
fallbackFactory=void}

Step 1 : FeignClientFactoryBean 调用主流程

主调流程为 :

  • FeignClientFactoryBean.getObject
  • FeignClientFactoryBean.getTarget
  • FeignClientFactoryBean.loadBalance
  • HystrixTargeter.target
  • ReflectiveFeign.newInstance :

这里看到 , 这里的起点是 getObject , 该方法是一个重写方法 , 源头为接口 FactoryBean < Object >

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
java复制代码C09- FeignClientFactoryBean
M09_01- getTarget
1- this.applicationContext.getBean(FeignContext.class) : 获取Feign 核心容器
2- 通过容器配置获取 Feign.Builder 对象
3- 最终调用 loadBalance 进行负载均衡的封装


<T> T getTarget() {
// 1 . 准备了 FeignContext
FeignContext context = this.applicationContext.getBean(FeignContext.class);
// 2 . 准备了 Feign.Builder
Feign.Builder builder = feign(context);

//
if (!StringUtils.hasText(this.url)) {
if (!this.name.startsWith("http")) {
this.url = "http://" + this.name;
} else {
this.url = this.name;
}
this.url += cleanPath();
// 通常情况下 , URL 不为空 , 会总结返回 loadBalance 对象
return (T) loadBalance(builder, context,
new HardCodedTarget<>(this.type, this.name, this.url));
}
if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {
this.url = "http://" + this.url;
}
String url = this.url + cleanPath();
// 此处获得连接的 client 对象
Client client = getOptional(context, Client.class);
if (client != null) {
if (client instanceof LoadBalancerFeignClient) {
client = ((LoadBalancerFeignClient) client).getDelegate();
}
if (client instanceof FeignBlockingLoadBalancerClient) {
client = ((FeignBlockingLoadBalancerClient) 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));
}

[Pro0001] : FeignContext 的作用 ?
创建虚类实例的工厂。它为每个客户端名称创建一个Spring ApplicationContext,并从中提取所需的bean.

[Pro0002] : Feign.Builder ?

这是一个 feign 构造工具 , 包含常用的配置信息和工具对象 , 例如最常见的 client 和 加密解密工具 ,
可以理解为一个集合体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
java复制代码public static class Builder {

private final List<RequestInterceptor> requestInterceptors =
new ArrayList<RequestInterceptor>();
private Logger.Level logLevel = Logger.Level.NONE;
private Contract contract = new Contract.Default();
private Client client = new Client.Default(null, null);
private Retryer retryer = new Retryer.Default();
private Logger logger = new NoOpLogger();
private Encoder encoder = new Encoder.Default();
private Decoder decoder = new Decoder.Default();
private QueryMapEncoder queryMapEncoder = new FieldQueryMapEncoder();
private ErrorDecoder errorDecoder = new ErrorDecoder.Default();
private Options options = new Options();
private InvocationHandlerFactory invocationHandlerFactory =
new InvocationHandlerFactory.Default();
private boolean decode404;
private boolean closeAfterDecode = true;
private ExceptionPropagationPolicy propagationPolicy = NONE;
private boolean forceDecoding = false;
private List<Capability> capabilities = new ArrayList<>();

}

Step 2 : loadBalance 构建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
java复制代码C09- FeignClientFactoryBean
M09_02- loadBalance
1- feign.Client 对象创建 (LoadBalancerFeignClient)
2- Targeter 创建 (HystrixTargeter)
3- targeter.target 处理 (包括 fallback , fallbackFactory , SetterFactory)

// PS : 在上一个步骤中 , 返回了一个 loadBalance 对象 >>>


protected <T> T loadBalance(Feign.Builder builder, FeignContext context,
HardCodedTarget<T> target) {
// LoadBalancerFeignClient
Client client = getOptional(context, Client.class);
if (client != null) {
builder.client(client);
// HystrixTargeter
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?");

}


// Targeter 是一个接口 , 主要有2个实现类 : HystrixTargeter , DefaultTargeter


}

[Pro] : getOptional 获取 Client

此处会根据我们之前初始化中说的 , 通过配置选择是否调用 OkHttpClient 或者 HttpClient , 配置后就会发现 , 实际上进入了如下类 :

1
2
3
4
5
6
7
8
java复制代码C- OkHttpFeignConfiguration
public okhttp3.OkHttpClient client(OkHttpClientFactory httpClientFactory,
ConnectionPool connectionPool,
FeignHttpClientProperties httpClientProperties) {

//......................

}

Step 3 : HystrixTargeter 的处理

因为之前的 Feign 就行 HystrixFeign ,所以通常这里会直接调用 feign.target(target);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
java复制代码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) {
return targetWithFallback(name, context, target, builder, fallback);
}
Class<?> fallbackFactory = factory.getFallbackFactory();
if (fallbackFactory != void.class) {
return targetWithFallbackFactory(name, context, target, builder,fallbackFactory);
}

return feign.target(target);
}

PS : 如果不是 HystrixFeign , 后续其实还是创建了一个 HystrixFeign

Step 4 : Invoke 代理类的构建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
java复制代码C30- ReflectiveFeign
M30_01- apply(Target target)
1- 获取 Method 元数据集合 List<MethodMetadata> -> PS:M30_01_01
2- 根据类型不同构建 BuildTemplateByResolvingArgs -> PS:M30_01_02
3- 构建 MethodHandler -> PS:M30_01_03
M30_02- newInstance(Target<T> target) -> PS:M30_02_03
1- 获取所有方法的 Map<String, MethodHandler> 集合 nameToHandler
// 对象准备
2- Map<Method, MethodHandler> methodToHandler -> LV:M30_02_01
3- List<DefaultMethodHandler> defaultMethodHandlers
// For 循环处理
4-FOR- nameToHandler (Map<String, MethodHandler>)
- methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)))
?- 添加到 LV:M30_02_01 methodToHandler 中
// 实体类构建
5- new ReflectiveFeign.FeignInvocationHandler(target, dispatch) : 构建代理对象 InvocationHandler
6- Proxy.newProxyInstance : 构建代理类 核心方法


// M30_01 源代码
public Map<String, MethodHandler> apply(Target target) {
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 {
// 构建 MethodHandler
result.put(md.configKey(),
// 此处的 factory 为 SynchronousMethodHandler.Factory (静态内部类)
factory.create(target, md, buildTemplate, options, decoder, errorDecoder));
}
}
return result;
}
}


// M30_02 源代码
public <T> T newInstance(Target<T> target) {
// 注意 , 此处直接调用了 apply
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)));
}
}
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;
}

PS:M30_01_01 元数据集合

Feign_client_method_meatadata.jpg

PS:M30_01_02 BuildTemplateByResolvingArgs 对象

Feign_client_build_template.jpg

PS:M30_01_03 MethodHandler 对象参数

可以看到 , 相关的参数均在里面了

feign_method_handler.jpg

总结

这一部分也不麻烦 ,总得来说就是生成了一个 Proxy ,对接口进行了代理

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%