if (StringUtils.hasText(qualifier)) {
alias = qualifier;
}
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, new String[]{alias});
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
}
}
FeignClientsRegistrar类的registerFeignClient()方法为扫描到的每一 《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》无偿开源 威信搜索公众号【编程进阶路】 个RPC客户端接口注册一个beanDefinition实例(Bean的),其中的beanClass为FeignClientFactoryBean。
registerFeignClient()方法的attributes参数值来自于RPC客户端接口
@FeignClient注解所配置的值,在该方法上设置断点,在uaa-provider启动时可以看到的attributes参数的具体信息如图3-19所示。
图3-19 registerFeignClient()方法的attributes参数值
Feign.Builder建造者容器实例
====================
当从Spring IOC容器获取RPC接口的动态代理实例时,也就是当FeignClientFactoryBean的getObject()方法被调用时,其调用的getTarget()方法首先从IOC容器获取配置好的Feign.Builder建造者容器实例,然后通过Feign.Builder建造者容器实例的target()方法完成RPC动态代理实例的创建。
说明
这里将Builder翻译为建造者,以便同构造器进行区分。
Feign.Builder建造者容器实例在自动配置类
FeignClientsConfiguration中完成配置,通过其源码可以看到,配置类的feignBuilder(…)方法通过调用Feign.builder()静态方法创建了一个建造者容器实例。
自动配置类FeignClientsConfiguration的部分源码如下:
package org.springframework.cloud.openfeign;
//省略import
//Feign客户端的配置类
@Configuration
public class FeignClientsConfiguration {
//容器实例:请求结果解码器
@Bean
@ConditionalOnMissingBean
public Decoder feignDecoder() {
return new OptionalDecoder(new ResponseEntityDecoder(
new SpringDecoder(this.messageConverters)));
}
//容器实例:请求编码器
@Bean
@ConditionalOnMissingBean
public Encoder feignEncoder() {
return new SpringEncoder(this.messageConverters);
}
//容器实例:请求重试实例,如果没有定制,就默认返回NEVER_RETRY(不重试)实例
@Bean
@ConditionalOnMissingBean
public Retryer feignRetryer() {
return Retryer.NEVER_RETRY;
} //容器实例:Feign.Builder客户端建造者实例,以“请求重试实例”作为参数进行初始化
@Bean
@Scope(“prototype”)
@ConditionalOnMissingBean
public Builder feignBuilder(Retryer retryer) {
return Feign.builder().retryer(retryer);
}
…
}
Feign.Builder类是feign.Feign抽象类的一个内部类,作为Feign默认的建造者。Feign.Builder类的部分源码如下:
package feign;
…
public abstract class Feign {
…
//建造者方法
public static Builder builder() {
return new Builder();
}
//内部类:建造者类
public static class Builder {
…
//创建RPC客户端的动态代理实例
public T target(Target target) {
return build().newInstance(target);
}
//建造方法
public Feign build() {
//方法处理器工厂的实例
SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
new SynchronousMethodHandler.Factory(client,
retryer,
requestInterceptors,
logger,
logLevel, decode404);
//RPC方法解析器
ParseHandlersByName handlersByName = new ParseHandlersByName
(contract, options, encoder, decoder, errorDecoder, synchronousMethodHandlerFactory);
//反射式Feign实例
return new ReflectiveFeign(handlersByName, invocationHandlerFactory);
}
}
当FeignClientFactoryBean工厂类的getObject()方法被调用后,通过Feign.Builder容器实例的target()方法完成RPC动态代理实例的创建。Feign.Builder的target()实例方法首先调用内部的build()方法创建一个Feign实例,然后通过该实例的newInstance(…)方法创建最终的RPC动态代理实例。默认情况下,所创建的Feign实例为ReflectiveFeign类型,二者的关系如图3-20所示。
图3-20 Feign和ReflectiveFeign二者之间的关系
这里通过单步断点演示一下。通过开发调试工具(如IDEA)在Feign.Builder的target(…)方法唯一的一行代码上设置一个断点,然后以调试模式启动uaa-provider服务,在工程启动的过程中可以看到断点所在的语句会被执行到。
断点被执行到之后,通过IDEA的Evaluate工具计算一下target()方法运行时的target实参值,可以看到,它的实参值就是对DemoClient远程接口信息的一种二次封装,如图3-21所示。
图3-21 DemoClient动态代理实例创建时的target()方法处的断点信息
总结一下,当从Spring容器获取RPC接口的动态代理实例时,对应的FeignClientFactoryBean的getObject()方法会被调用到,然后通过Feign.Builder建造者容器实例的target()方法创建RPC接口的动态代理实例,并缓存到Spring IOC容器中。
默认的RPC动态代理实例的创建流程
==================
默认情况下,Feign.Builder建造者实例的target()方法会调用自身的build()方法创建一个ReflectiveFeign(反射式Feign)实例,然后调用该实例的newInstance()方法创建远程接口最终的JDK动态代理实例。
ReflectiveFeign(反射式Feign)类的实例的newInstance()方法创建RPC动态代理实例的具体步骤是什么呢?先看看ReflectiveFeign的源码,具体如下:
package feign;
//省略import
public class ReflectiveFeign extends Feign {
//方法解析器
private final ParseHandlersByName targetToHandlersByName;
//调用处理器工厂
private final InvocationHandlerFactory factory;
…
//创建RPC客户端动态代理实例
public T newInstance(Target target) {
//方法解析: 方法名和方法处理器的映射
Map
//方法反射对象和方法处理器的映射
Map
…
//创建一个InvocationHandler调用处理器
InvocationHandler handler = factory.create(target, methodToHandler);
//最后调用JDK的Proxy.newProxyInstance创建代理对象
T proxy = (T) Proxy.newProxyInstance(
target.type().getClassLoader(), new Class>[]{target.type()}, handler);
…
//返回代理对象
return proxy;
}
终于看到Feign动态代理类实例的创建逻辑了,以上默认的Feign RPC动态代理客户端实例的创建流程和前面介绍的模拟动态代理RPC客户端实例的创建流程大致相似。
简单来说,默认的Feign RPC动态代理客户端实例的创建流程大致为以下4步:
(1)方法解析。解析远程接口中的所有方法,为每一个方法创建一个MethodHandler方法处理器,然后进行方法名称和方法处理器的Key-Value(键-值)映射nameToHandler。
(2)创建方法反射实例和方法处理器的映射。
通过方法名称和方法处理器的映射nameToHandler创建一个方法反射实例到方法处理器的Key-Value映射methodToHandler,作为方法远程调用时的分发处理映射实例。
(3)创建一个JDK调用处理器。
主要以methodToHandler为参数,创建一个InvocationHandler调用处理器实例。
(4)创建一个动态代理对象。
调用JDK的Proxy.newProxyInstance()方法创建一个动态代理实例,它的参数有3个:RPC远程接口的类装载器、RPC远程接口的Class实例以及上一步创建的InvocationHandler调用处理器实例。
远程接口的RPC动态代理实例的创建流程如图3-22所示。
图3-22 远程接口的RPC动态代理实例的创建流程
以上创建RPC动态代理客户端实例的4个步骤是需要理解和掌握的重点内容,后面的介绍会根据这4个步骤展开。
在
ReflectiveFeign.newInstance()方法中首先调用了ParseHandlersByName.apply()方法,解析RPC接口中的所有RPC方法配置(通过Contract解析),然后为每个RPC方法创建一个对应的MethodHandler方法处理器。
默认的ParseHandlersByName方法解析器是ReflectiveFeign(反射式Feign)类的一个内部类,它的源码如下:
package feign;
//省略import
public class ReflectiveFeign extends Feign {
…
//内部类:方法解析器
static final class ParseHandlersByName {
//同步方法处理器工厂
private final SynchronousMethodHandler.Factory factory;
…
//RPC接口元数据解析
public Map
//解析RPC方法元数据,返回一个方法元数据列表
List metadata =
contract.parseAndValidatateMetadata(key.type());
Map
new LinkedHashMap
//迭代RPC方法元数据列表
for (MethodMetadata md : metadata) {
…
//通过方法处理器工厂factory创建SynchronousMethodHandler同步方法处理实例
result.put(md.configKey(),
factory.create(key, md, buildTemplate, options, decoder, errorDecoder));
}
return result;
}
}
通过以上源码可以看到,方法解析器ParseHandlersByName创建方法处理器的过程是通过方法处理器工厂类实例factory的create()方法完成的。而默认的方法处理器工厂类Factory定义在SynchronousMethodHandler类中,其代码如下:
package feign;
//省略import
final class SynchronousMethodHandler implements MethodHandler {…
static class Factory {
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);
}
…
}
通过以上源码可以看出,通过默认方法处理器工厂类Factory的create()方法创建的正是同步方法处理器SynchronousMethodHandler的实例。
接下来,简单介绍一下FeignInvocationHandler调用处理器的创建。和方法处理器类似,它的创建也是通过工厂模式完成的。默认的InvocationHandler实例是通过InvocationHandlerFactory工厂类完成的。该工厂类的源码大致如下:
package feign;
//调用处理器工厂接口
public interface InvocationHandlerFactory {
InvocationHandler create(Target target, Map
…
//默认实现类
static final class Default implements InvocationHandlerFactory {
//通过内部类FeignInvocationHandler构造一个默认的调用处理器
@Override
public InvocationHandler create(Target target, Map
return new ReflectiveFeign.FeignInvocationHandler(target, dispatch);
}
}
}
在上面的源码中,调用处理器工厂InvocationHandlerFactory仅仅是一个接口,只定义了一个唯一的create()方法,用于创建InvocationHandler调用处理器实例。
InvocationHandlerFactory工厂类提供了一个默认的实现类——Default内部类,其create()方法所创建的调用处理器实例就是前文反复提及的,也就是做过重点介绍的Feign的默认调用处理器类FeignInvocationHandler类的实例。
Contract远程调用协议规则类
=================
在通过
ReflectiveFeign.newInstance()方法创建本地JDK Proxy实例时,首先需要调用方法解析器ParseHandlersByName的apply()方法,获取方法名和方法处理器的映射。