专栏系列文章:SpringCloud系列专栏
系列文章:
SpringCloud 源码系列(1)— 注册中心Eureka 之 启动初始化
SpringCloud 源码系列(2)— 注册中心Eureka 之 服务注册、续约
SpringCloud 源码系列(3)— 注册中心Eureka 之 抓取注册表
SpringCloud 源码系列(4)— 注册中心Eureka 之 服务下线、故障、自我保护机制
SpringCloud 源码系列(5)— 注册中心Eureka 之 EurekaServer集群
SpringCloud 源码系列(6)— 注册中心Eureka 之 总结篇
SpringCloud 源码系列(7)— 负载均衡Ribbon 之 RestTemplate
SpringCloud 源码系列(8)— 负载均衡Ribbon 之 核心原理
SpringCloud 源码系列(9)— 负载均衡Ribbon 之 核心组件与配置
SpringCloud 源码系列(10)— 负载均衡Ribbon 之 HTTP客户端组件
SpringCloud 源码系列(11)— 负载均衡Ribbon 之 重试与总结篇
SpringCloud 源码系列(12)— 服务调用Feign 之 基础使用篇
SpringCloud 源码系列(13)— 服务调用Feign 之 扫描@FeignClient注解接口
动态代理工厂组件 FeignClientFactoryBean
从前文中已经分析出 FeignClientFactoryBean
这个组件就是生成 FeignClient 接口动态代理的组件。
FeignClientFactoryBean 实现了 FactoryBean
接口,当一个Bean实现了 FactoryBean 接口后,Spring 会先实例化这个工厂,然后在需要的时候调用 getObject()
创建真正的Bean。
class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean, ApplicationContextAware {
}
FeignClientFactoryBean 实现了 getObject()
方法,它又调用了 getTarget()
方法,getTarget()
最后就创建了 FeignClient 接口的动态代理对象。
创建动态代理对象的主要流程如下:
- 首先获取了 Feign 上下文
FeignContext
,FeignContext 跟 Ribbon 中SpringClientFactory
是类似的,可以获取到每个服务的上下文。因为每个服务都有自己的配置、Encoder、Decoder 组件等,所以可以从 FeignContext 中获取到当前服务的组件。 - 然后从 FeignContext 中得到了
Feign.Builder
,这个 Feign.Builder 就是最终用来创建动态代理对象的构造器。 - @FeignClient 如果没有配置
url
,就会通过服务名称构造带服务名的url地址,跟 RestTemplate 类似,最终肯定就是走负载均衡的请求;如果配置了 url,就是直接调用这个地址。 - 都会从 FeignContext 中获取一个
Client
,如果配置了 url,就是获取 client 里的代理对象
,并设置到 builder 中;否则就直接将 Client 设置到 builder。也就是说根据 url 判断是否使用负载均衡的 Client。 - 最终都会调用 Targeter 的
target()
方法来构造动态代理对象,target 传入的参数包括当前的 FeignClientFactoryBean 对象、Feign.Builder、FeignContext,以及封装的HardCodedTarget
对象。
// 获取 FeignClient 代理对象的入口
@Override
public Object getObject() throws Exception {
return getTarget();
}
/**
* 创建一个 FeignClient 接口的代理对象,T 就是 @FeignClient 注解的接口类型
*
* @param <T> the target type of the Feign client
* @return a {@link Feign} client created with the specified data and the context information
*/
<T> T getTarget() {
// Feign 上下文
FeignContext context = applicationContext.getBean(FeignContext.class);
// Feign 构造器
Feign.Builder builder = feign(context);
// 如果没有直接配置 url,就走负载均衡请求
if (!StringUtils.hasText(url)) {
if (!name.startsWith("http")) {
url = "http://" + name;
}
else {
url = name;
}
// 带服务名的地址 => http://demo-consumer
url += cleanPath();
// 返回的类型肯定是具备负载均衡能力的;HardCodedTarget => 硬编码的 Target
return (T) loadBalance(builder, context, new HardCodedTarget<>(type, name, url));
}
// 如果配置了 url,就直接请求 url 地址
if (StringUtils.hasText(url) && !url.startsWith("http")) {
url = "http://" + url;
}
String url = this.url + cleanPath();
// Client => Feign 发起 HTTP 调用的核心组件
Client client = getOptional(context, Client.class);
if (client != null) {
if (client instanceof LoadBalancerFeignClient) {
// 得到的是代理对象,就是原生的 Client.Default
client = ((LoadBalancerFeignClient) client).getDelegate();
}
if (client instanceof FeignBlockingLoadBalancerClient) {
// 得到的是代理对象,就是原生的 Client.Default
client = ((FeignBlockingLoadBalancerClient) client).getDelegate();
}
builder.client(client);
}
Targeter targeter = get(context, Targeter.class);
// targeter 创建动态代理对象
return (T) targeter.target(this, builder, context, new HardCodedTarget<>(type, name, url));
}
protected <T> T loadBalance(Feign.Builder builder, FeignContext context, HardCodedTarget<T> target) {
// 获取 Client
Client client = getOptional(context, Client.class);
if (client != null) {
builder.client(client);
// Targeter => HystrixTargeter
Targeter targeter = get(context, Targeter.class);
// targeter 创建动态代理对象
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?");
}
动态代理构造器 Feign.Builder
feign()
方法返回了 Feign.Builder
,它也是从 FeignContext 中获取的,这个方法最重要的是设置了 Logger、Encoder、Decoder、Contract
,并读取配置文件中 feign.client.*
相关的配置。FeignClientsConfiguration 中配置了这几个接口的默认实现类,我们也可以自定义这几个实现类。
protected Feign.Builder feign(FeignContext context) {
FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);
Logger logger = loggerFactory.create(type);
// 我们可以定制 Logger、Encoder、Decoder、Contract
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));
// 读取配置文件中 feign.client.* 的配置来配置 Feign
configureFeign(context, builder);
return builder;
}
Feign.Builder
的默认实现是什么呢?从 FeignClientsConfiguration 中可以知道,默认情况下就是 Feign.Builder
,如果启用了 feign.hystrix.enabled
,那默认实现就是 HystrixFeign.Builder
。
那 Feign.Builder 和 HystrixFeign.Build 有什么区别呢?对比下不难发现,主要区别就是创建动态代理的实现类 InvocationHandler
是不同的,在启用 hystrix 的情况下,会涉及到熔断、降级等,HystrixFeign.Build 也会设置 @FeignClient 配置的 fallback、fallbackFactory
降级配置类。这块等后面分析 hystrix 源码时再来看。现在只需要知道,feign 没有启用 hystrix,@FeignClient 配置的 fallback、fallbackFactory 降级回调是不生效的。
public class FeignClientsConfiguration {
@Bean
@ConditionalOnMissingBean
public Retryer feignRetryer() {
// 从不重试
return Retryer.NEVER_RETRY;
}
@Bean
@Scope("prototype")
@ConditionalOnMissingBean
public Feign.Builder feignBuilder(Retryer retryer) {
// 默认为 Feign.Builder
return Feign.builder().retryer(retryer);
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ HystrixCommand.class, HystrixFeign.class })
protected static class HystrixFeignConfiguration {
// 引入了 hystrix 并且,feign.hystrix.enabled = true
@Bean
@Scope("prototype")
@ConditionalOnMissingBean
@ConditionalOnProperty(name = "feign.hystrix.enabled")
public Feign.Builder feignHystrixBuilder() {
// feign 启用 hystrix 后,Feign.Builder 就是 HystrixFeign.Builder
return HystrixFeign.builder();
}
}
}
feign 配置
configureFeign()
方法就是配置 Feign.Builder 的,从这个方法可以验证基础篇文章中 feign 配置生效的优先级。
Feign 有三块配置,一个是可以通过 Configuration 的方式配置,然后设置到 @FeignClient 的 configuration
参数;然后是全局的 feign.client.default
默认配置,以及服务特定的配置 feign.client.<clientName>
。
从 configureFeign()
方法可以看出,默认情况下,优先级最低的是代码配置,其次是默认配置,最高优先级的是服务特定的配置
。
如果想使代码配置优先级高于文件中的配置,可以设置 feign.client.defalut-to-properties=false
来改变 Feign 配置生效的优先级。
protected void configureFeign(FeignContext context, Feign.Builder builder) {
// 配置文件中 feign.client.* 客户端配置
FeignClientProperties properties = applicationContext.getBean(FeignClientProperties.class);
FeignClientConfigurer feignClientConfigurer = getOptional(context, FeignClientConfigurer.class);
setInheritParentContext(feignClientConfigurer.inheritParentConfiguration());
if (properties != null && inheritParentContext) {
// defaultToProperties:优先使用配置文件中的配置
if (properties.isDefaultToProperties()) {
// 最低优先级:使用代码中的 Configuration 配置
configureUsingConfiguration(context, builder);
// 次优先级:使用 feign.client.default 默认配置
configureUsingProperties(properties.getConfig().get(properties.getDefaultConfig()), builder);
// 高优先级:使用 feign.client.<clientName> 定义的配置
configureUsingProperties(properties.getConfig().get(contextId), builder);
}
// 优先使用Java代码的配置
else {
configureUsingProperties(properties.getConfig().get(properties.getDefaultConfig()), builder);
configureUsingProperties(properties.getConfig().get(contextId), builder);
configureUsingConfiguration(context, builder);
}
}
else {
configureUsingConfiguration(context, builder);
}
}
网络调用组件 Client
Client
是 feign-core
中的组件,它只有一个接口 execute
,这个接口就是调用 Request
的 url,然后将返回接口封装到 Response
中。
public interface Client {
/**
* Executes a request against its {@link Request#url() url} and returns a response.
*
* @param request safe to replay.
* @param options options to apply to this request.
* @return connected response, {@link Response.Body} is absent or unread.
* @throws IOException on a network error connecting to {@link Request#url()}.
*/
Response execute(Request request, Options options) throws IOException;
}
Client 有如下的一些实现类:
Client 的自动化配置类是 FeignRibbonClientAutoConfiguration
,FeignRibbonClientAutoConfiguration 导入了 HttpClient、OkHttp 以及默认的 Feign 负载均衡配置类。
@ConditionalOnClass({ ILoadBalancer.class, Feign.class })
@ConditionalOnProperty(value = "spring.cloud.loadbalancer.ribbon.enabled", matchIfMissing = true)
@Configuration(proxyBeanMethods = false)
@AutoConfigureBefore(FeignAutoConfiguration.class)
@EnableConfigurationProperties({ FeignHttpClientProperties.class })
@Import({ HttpClientFeignLoadBalancedConfiguration.class,
OkHttpFeignLoadBalancedConfiguration.class,
DefaultFeignLoadBalancedConfiguration.class })
public class FeignRibbonClientAutoConfiguration {
}
启用 Apache HttpClient
从 HttpClientFeignLoadBalancedConfiguration
的配置可以看出,要启用 apache httpclient,需设置 feign.httpclient.enabled=true
(默认为 true),并且需要加入了 feign-httpclient
的依赖(ApacheHttpClient)
启用 apache httpclient 后,LoadBalancerFeignClient
的代理对象就是 feign-httpclient 中的 ApacheHttpClient
。
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ApacheHttpClient.class)
@ConditionalOnProperty(value = "feign.httpclient.enabled", matchIfMissing = true)
@Import(HttpClientFeignConfiguration.class)
class HttpClientFeignLoadBalancedConfiguration {
@Bean
@ConditionalOnMissingBean(Client.class)
public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
SpringClientFactory clientFactory, HttpClient httpClient) {
ApacheHttpClient delegate = new ApacheHttpClient(httpClient);
return new LoadBalancerFeignClient(delegate, cachingFactory, clientFactory);
}
}
启用 OkHttp
从 OkHttpFeignLoadBalancedConfiguration
的配置可以看出,要启用 okhttp,需设置 feign.okhttp.enabled=true
,且需要引入 feign-okhttp
的依赖(OkHttpClient)。
启用 okhttp 后,LoadBalancerFeignClient
的代理对象就是 feign-okhttp 的 OkHttpClient
。
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(OkHttpClient.class)
@ConditionalOnProperty("feign.okhttp.enabled")
@Import(OkHttpFeignConfiguration.class)
class OkHttpFeignLoadBalancedConfiguration {
@Bean
@ConditionalOnMissingBean(Client.class)
public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
SpringClientFactory clientFactory, okhttp3.OkHttpClient okHttpClient) {
OkHttpClient delegate = new OkHttpClient(okHttpClient);
return new LoadBalancerFeignClient(delegate, cachingFactory, clientFactory);
}
}
默认配置
没有引入 feign-httpclient
或者 feign-okhttp
,就会走默认的 DefaultFeignLoadBalancedConfiguration
。而默认的代理对象 Client.Default
其实就是使用 HttpURLConnection
发起 HTTP 调用。
@Configuration(proxyBeanMethods = false)
class DefaultFeignLoadBalancedConfiguration {
@Bean
@ConditionalOnMissingBean
public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
SpringClientFactory clientFactory) {
return new LoadBalancerFeignClient(new Client.Default(null, null), cachingFactory, clientFactory);
}
}
可以看出,三个配置类创建的 Client 对象都是 LoadBalancerFeignClient
,也就是支持负载均衡的请求。只是代理类不同,也就是最终发起 HTTP 调用的组件是不同的,默认配置下的代理类是 Client.Default,底层就是 HttpURLConnection。
这块其实跟分析 Ribbon 源码时,RestTemplate 的负载均衡是类似的。
动态代理目标器 Targeter
Targeter
接口只有一个接口方法,就是通过 target()
方法获取动态代理对象。Targeter 有 DefaultTargeter、HystrixTargeter
两个实现类,
interface Targeter {
<T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
FeignContext context, Target.HardCodedTarget<T> target);
}
在 FeignAutoConfiguration
配置类中可看到,只要引入了 HystrixFeign
,Targeter 的默认实现就是 HystrixTargeter
。
HystrixTargeter 一看就是用来整合 feign 和 hystrix 的,使 feign 调用可以实现熔断、限流、降级。
public class FeignAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(name = "feign.hystrix.HystrixFeign")
protected static class HystrixFeignTargeterConfiguration {
@Bean
@ConditionalOnMissingBean
public Targeter feignTargeter() {
return new HystrixTargeter();
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingClass("feign.hystrix.HystrixFeign")
protected static class DefaultFeignTargeterConfiguration {
@Bean
@ConditionalOnMissingBean
public Targeter feignTargeter() {
return new DefaultTargeter();
}
}
}
可以看到 HystrixTargeter 和 DefaultTargeter 的区别就在于 HystrixTargeter 会向 Feign.Builder
设置降级回调处理类,这样 feign 调用触发熔断、降级时,就可以进入回调类处理。
它们本质上最终来说都是调用 Feign.Builder 的 target()
方法创建动态代理对象。
class HystrixTargeter implements Targeter {
@Override
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
FeignContext context, Target.HardCodedTarget<T> target) {
if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) {
// 非 HystrixFeign.Builder 类型,就直接调用 target 方法
return feign.target(target);
}
// Feign 启用了 hystrix 后,就会向 HystrixFeign.Builder 设置回调类或回调工厂
feign.hystrix.HystrixFeign.Builder builder = (feign.hystrix.HystrixFeign.Builder) feign;
String name = StringUtils.isEmpty(factory.getContextId()) ? factory.getName() : factory.getContextId();
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);
}
// 调用 Feign.Builder 创建动态代理
return feign.target(target);
}
}
class DefaultTargeter implements Targeter {
@Override
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
FeignContext context, Target.HardCodedTarget<T> target) {
return feign.target(target);
}
}
Feign.Builder 创建动态代理
前面已经分析出,Feign.Builder 的默认实现就是 Feign.Builder,HystrixTargeter 中调用了 Feign.Builder 的 target
方法来创建动态代理。
- target 方法中首先调用
build()
方法构建出Feign
,然后调用 Feign 的newInstance
创建动态代理对象。 build()
方法中首先读取配置的Client、Retryer、Logger、Contract、Encoder、Decoder
等对象。- 然后获取了
InvocationHandlerFactory
,默认就是InvocationHandlerFactory.Default
,这是 feign 提供的一个工厂类来创建代理对象InvocationHandler
。 - 接着创建了接口方法处理器工厂
SynchronousMethodHandler.Factory
,它就是用来将接口方法封装成一个方法执行器MethodHandler
,默认实现类是SynchronousMethodHandler
。 - 还创建了 springmvc 注解处理器
ParseHandlersByName
,可想而知,这就是用来处理接口中的 springmvc 注解的,将 REST 接口解析生成 MethodHandler。 - 最后创建了 Feign 对象,实现类是 ReflectiveFeign,之后就是使用 ReflectiveFeign 来创建动态代理对象了。
public <T> T target(Target<T> target) {
return build().newInstance(target);
}
// 构建 Feign
public Feign build() {
// Feign Http调用客户端,默认为 Client.Default
Client client = Capability.enrich(this.client, capabilities);
// 重试器,默认是重不重试
Retryer retryer = Capability.enrich(this.retryer, capabilities);
// Feign 请求拦截器,可以对 Feign 请求模板RequestTemplate做一些定制化处理
List<RequestInterceptor> requestInterceptors = this.requestInterceptors.stream()
.map(ri -> Capability.enrich(ri, capabilities))
.collect(Collectors.toList());
// 日志组件,默认为 Slf4jLogger
Logger logger = Capability.enrich(this.logger, capabilities);
// 接口协议组件,默认为 SpringMvcContract
Contract contract = Capability.enrich(this.contract, capabilities);
// 配置类
Options options = Capability.enrich(this.options, capabilities);
// 编码器
Encoder encoder = Capability.enrich(this.encoder, capabilities);
// 解码器
Decoder decoder = Capability.enrich(this.decoder, capabilities);
// 创建 InvocationHandler 的工厂类
InvocationHandlerFactory invocationHandlerFactory =
Capability.enrich(this.invocationHandlerFactory, capabilities);
QueryMapEncoder queryMapEncoder = Capability.enrich(this.queryMapEncoder, capabilities);
// 接口方法处理器工厂
SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
logLevel, decode404, closeAfterDecode, propagationPolicy, forceDecoding);
// 解析 springmvc 注解
ParseHandlersByName handlersByName =
new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,
errorDecoder, synchronousMethodHandlerFactory);
// ReflectiveFeign
return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
}
InvocationHandlerFactory
包含一个 create
接口方法,默认实现是 InvocationHandlerFactory.Default,返回的 InvocationHandler 类型是 ReflectiveFeign.FeignInvocationHandler
。
package feign;
public interface InvocationHandlerFactory {
// 创建动态代理
InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch);
// 方法处理器
interface MethodHandler {
Object invoke(Object[] argv) throws Throwable;
}
static final class Default implements InvocationHandlerFactory {
@Override
public InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch) {
return new ReflectiveFeign.FeignInvocationHandler(target, dispatch);
}
}
}
接着看 ReflectiveFeign 的 newInstance()
方法:
newInstance
的参数 target 就是前面封装的Target.HardCodedTarget
,它封装了客户端的类型、url
等属性。- 首先是使用
ParseHandlersByName
将 FeignClient 接口中的接口转换成 MethodHandler,实际类型就是SynchronousMethodHandler
,这个细节就不在看了。 - 然后用
InvocationHandlerFactory
创建 InvocationHandler 代理对象,也就是ReflectiveFeign.FeignInvocationHandler
,调用动态代理对象的方法,最终都会进入到这个执行处理器里面。 - 最后,终于看到创建动态代理的地方了,使用
Proxy
创建了 FeignClient 的动态代理对象,这个动态代理的类型就是 @FeignClient 注解的接口的类型。最后被注入到 IoC 容器后,就可以在代码中注入自己编写的 FeignClient 客户端组件了。
最终就是通过 Proxy
创建一个实现了 FeignClient 接口的动态代理,然后所有接口方法的调用都会被 FeignInvocationHandler
拦截处理。
public <T> T newInstance(Target<T> target) {
// 使用 ParseHandlersByName 将 FeignClient 接口中的接口转换成 MethodHandler,springmvc 注解由 Contract 组件处理
// MethodHandler => SynchronousMethodHandler
Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();
List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>();
// 转换成 Method - MethodHandler 映射
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)));
}
}
// 用 SynchronousMethodHandler.Factory 创建 SynchronousMethodHandler
InvocationHandler handler = factory.create(target, methodToHandler);
// 用 Proxy 创建动态代理,动态代理对象就是 SynchronousMethodHandler
T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
new Class<?>[] {target.type()}, handler);
for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
defaultMethodHandler.bindTo(proxy);
}
return proxy;
}
一张图总结 FeignClient 生成动态代理的流程
下面用一张图来总结下生成 FeignClient 动态代理的流程:
- 首先
@EnableFeignClients
导入的注册器FeignClientsRegistrar
会扫描@FeignClient
注解的接口,并生成FeingClientFactoryBean
的BeanDefinition
注册到容器中。最后会调用 FeingClientFactoryBean 的getObject
方法来获取接口的动态代理对象。 - 进入 FeingClientFactoryBean 的 getObject 方法,首先获取了
FeignContext
,它其实就是每个客户端的容器,类似于一个 Map 结构,缓存了客户端与容器间的关系,后续大部分组件都是从 FeignContext 中获取。 - 从 FeignContext 中获取 Feign 构造器
Feign.Builder
,并配置 Feign.Builder,配置来源有多个地方,优先级最高的是 application.yml 中的配置生效;也可以配置feign.client.default-to-properties=false
设置Java代码配置为高优先级。 - 接下来就要根据 @FeignClient 是否配置了 url 决定是否走负载均衡的请求,其实就是设置的 Client 不一样:
- 如果配置了 url,表示一个具体的地址,就使用将 LoadBalancerFeignClient 的 delegate 作为 Client 设置给 Feign.Builder。
- 如果没有配置 url,表示通过服务名请求,就将 LoadBalancerFeignClient 作为 Client 设置给 Feign.Builder。
- 再从 FeignContext 中获取
Targeter
,调用它的target
方法来获取动态代理。 - 在 target 方法中,先调用 Feign.Builder 的
build()
方法构建了ReflectiveFeign
:- 先是获取代理对象工厂
InvocationHandlerFactory
,用于创建InvocationHandler
- 然后用各个组件,构造了方法处理器工厂
SynchronousMethodHandler.Factory
,接着创建了方法解析器ParseHandlersByName
- 最后基于 InvocationHandlerFactory 和 ParseHandlersByName 构造了
ReflectiveFeign
- 先是获取代理对象工厂
- 最后调用 ReflectiveFeign 的
newInstance
方法反射创建接口的动态代理:- 先用方法解析器 ParseHandlersByName 解析接口,将接口解析成
SynchronousMethodHandler
- 接着使用 InvocationHandlerFactory 创建了代理对象
InvocationHandler
(ReflectiveFeign.FeignInvocationHandler) - 最终用
Proxy
创建动态代理对象,对象的类型就是接口的类型,代理对象就是ReflectiveFeign.FeignInvocationHandler
。
- 先用方法解析器 ParseHandlersByName 解析接口,将接口解析成