这是我参与更文挑战的第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 对象
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 方法中看到
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 >
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 和 加密解密工具 ,
可以理解为一个集合体
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 构建
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 , 配置后就会发现 , 实际上进入了如下类 :
C- OkHttpFeignConfiguration
public okhttp3.OkHttpClient client(OkHttpClientFactory httpClientFactory,
ConnectionPool connectionPool,
FeignHttpClientProperties httpClientProperties) {
//......................
}
复制代码
Step 3 : HystrixTargeter 的处理
因为之前的 Feign 就行 HystrixFeign ,所以通常这里会直接调用 feign.target(target);
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 代理类的构建
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 元数据集合
PS:M30_01_02 BuildTemplateByResolvingArgs 对象
PS:M30_01_03 MethodHandler 对象参数
可以看到 , 相关的参数均在里面了
总结
这一部分也不麻烦 ,总得来说就是生成了一个 Proxy ,对接口进行了代理