feign的调用流程
读取注解信息:enablefeignclients-->feignclientsregistrar-->feignclientfactorybean
feigh流程:reflectivefeign-->contract-->synchronousmethodhandler
相关configuration:feignclientsconfiguration,feignautoconfiguration,defaultfeignloadbalancedconfiguration,feignribbonclientautoconfiguration(ribbon)
在feignclientsregistrar中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
@override
public void registerbeandefinitions(annotationmetadata metadata,
beandefinitionregistry registry) {
//注册feign配置信息
registerdefaultconfiguration(metadata, registry);
//注册feign client
registerfeignclients(metadata, registry);
}
private void registerfeignclient(beandefinitionregistry registry,
annotationmetadata annotationmetadata, map<string, object> attributes) {
string classname = annotationmetadata.getclassname();
//准备注入feignclientfactorybean
beandefinitionbuilder definition = beandefinitionbuilder
.genericbeandefinition(feignclientfactorybean. class );
...
}
|
查看feignclientfactorybean:
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
|
@override
public object getobject() throws exception {
feigncontext context = applicationcontext.getbean(feigncontext. class );
//构建feign.builder
feign.builder builder = feign(context);
//如果注解没有指定url
if (!stringutils.hastext( this .url)) {
string url;
if (! this .name.startswith( "http" )) {
url = "http://" + this .name;
}
else {
url = this .name;
}
url += cleanpath();
return loadbalance(builder, context, new hardcodedtarget<>( this .type,
this .name, 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) {
// 因为指定了url且classpath下有ribbon,获取client的delegate(unwrap)
// 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 targeter.target( this , builder, context, new hardcodedtarget<>(
this .type, this .name, url));
}
protected <t> t loadbalance(feign.builder builder, feigncontext context,
hardcodedtarget<t> target) {
//获取feign client实例
client client = getoptional(context, client. class );
if (client != null ) {
builder.client(client);
//defaulttargeter或者hystrixtargeter
targeter targeter = get(context, targeter. class );
//调用builder的target,其中就调用了feign的newinstance
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?" );
}
|
在feignclientsconfiguration配置了feign.builder,prototype类型:
1
2
3
4
5
6
|
@bean
@scope ( "prototype" )
@conditionalonmissingbean
public feign.builder feignbuilder(retryer retryer) {
return feign.builder().retryer(retryer);
}
|
feign的builder.build返回了一个reflectivefeign:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
public feign build() {
synchronousmethodhandler.factory synchronousmethodhandlerfactory =
new synchronousmethodhandler.factory(client, retryer, requestinterceptors, logger,
loglevel, decode404);
parsehandlersbyname handlersbyname =
new parsehandlersbyname(contract, options, encoder, decoder,
errordecoder, synchronousmethodhandlerfactory);
//reflectivefeign构造参数
//parsehandlersbyname作用是通过传入的target返回代理接口下的方法的各种信息(methodhandler)
//contract:解析接口的方法注解规则,生成methodmetadata
//options:request超时配置
//encoder:请求编码器
//decoder:返回解码器
//errordecoder:错误解码器
//synchronousmethodhandler.factory是构建synchronousmethodhandler的工厂
//client:代表真正执行http的组件
//retryer:该组决定了在http请求失败时是否需要重试
//requestinterceptor:请求前的拦截器
//logger:记录日志组件,包含各个阶段记录日志的方法和留给用户自己实现的log方法
//logger.level:日志级别
//decode404:处理404的策略,返回空还是报错
//synchronousmethodhandlerfactory通过所有的信息去包装一个synchronousmethodhandler,在调用invoke方法的时候执行http
return new reflectivefeign(handlersbyname, invocationhandlerfactory);
}
|
在调用feign.builder的target的时候,调用了reflectivefeign.newinstance:
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
|
/**
* creates an api binding to the {@code target}. as this invokes reflection, care should be taken
* to cache the result.
*/
@suppresswarnings ( "unchecked" )
@override
//接收target参数(包含feign代理接口的类型class,名称,http url)
public <t> t newinstance(target<t> target) {
//首先通过**parsehandlersbyname**解析出接口中包含的方法,包装requesttemplate,组装成<name, methodhandler>
map<string, methodhandler> nametohandler = targettohandlersbyname.apply(target);
map<method, methodhandler> methodtohandler = new linkedhashmap<method, methodhandler>();
//接口default方法list
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)));
}
}
//invocationhandlerfactory.default()返回了一个reflectivefeign.feigninvocationhandler对象,通过传入的methodhandler map 调用目标对象的对应方法
invocationhandler handler = factory.create(target, methodtohandler);
//生成jdk代理对象
t proxy = (t) proxy.newproxyinstance(target.type().getclassloader(), new class <?>[]{target.type()}, handler);
//绑定接口的默认方法到代理对象
for (defaultmethodhandler defaultmethodhandler : defaultmethodhandlers) {
defaultmethodhandler.bindto(proxy);
}
return proxy;
}
|
生成feign代理对象的基本流程图:
当调用接口方法时,实际上就是调用代理对象invoke方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
@override
public object invoke(object[] argv) throws throwable {
//工厂创建请求模版
requesttemplate template = buildtemplatefromargs.create(argv);
//每次克隆一个新的retryer
retryer retryer = this .retryer.clone();
while ( true ) {
try {
//这里调用实际的feign client execute
return executeanddecode(template);
} catch (retryableexception e) {
//失败重试
retryer.continueorpropagate(e);
if (loglevel != logger.level.none) {
logger.logretry(metadata.configkey(), loglevel);
}
continue ;
}
}
}
|
在defaultfeignloadbalancedconfiguration里实例化了loadbalancerfeignclient
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
@override
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);
//delegate这里是client.default实例,底层调用的是java.net原生网络访问
feignloadbalancer.ribbonrequest ribbonrequest = new feignloadbalancer.ribbonrequest(
this .delegate, request, uriwithouthost);
iclientconfig requestconfig = getclientconfig(options, clientname);
//executewithloadbalancer会根据ribbon的负载均衡算法构建url,这里不展开
return lbclient(clientname).executewithloadbalancer(ribbonrequest,
requestconfig).toresponse();
}
catch (clientexception e) {
ioexception io = findioexception(e);
if (io != null ) {
throw io;
}
throw new runtimeexception(e);
}
}
|
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://segmentfault.com/a/1190000018077675