启用 @EnableFeignClients
时会 @import
一个 FeignClientsRegistrar.class
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients
在 FeignClientsRegistrar 中,通过 #registerBeanDefinitions 方法中调用 #registerFeignClients 进行 FeignClient 注册
class FeignClientsRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
registerDefaultConfiguration(metadata, registry);
registerFeignClients(metadata, registry);
}
}
#registerFeignClients 则优先判断 @EnableFeignClients
注解中是否指定了 clients 属性,如果指定了,则仅导入 clients 中指定的类,如果未指定,则启用 scanner 扫描 @FeignClient
注解。最终,将 FeignClient 收到到 candidateComponents 集合中
LinkedHashSet<BeanDefinition> candidateComponents = new LinkedHashSet<>();
Map<String, Object> attrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName());
final Class<?>[] clients = attrs == null ? null : (Class<?>[]) attrs.get("clients");
if (clients == null || clients.length == 0) {
ClassPathScanningCandidateComponentProvider scanner = getScanner();
scanner.setResourceLoader(this.resourceLoader);
scanner.addIncludeFilter(new AnnotationTypeFilter(FeignClient.class));
Set<String> basePackages = getBasePackages(metadata);
for (String basePackage : basePackages) {
candidateComponents.addAll(scanner.findCandidateComponents(basePackage));
}
}else {
for (Class<?> clazz : clients) {
candidateComponents.add(new AnnotatedGenericBeanDefinition(clazz));
}
}
candidateComponents 收集完成后,遍历并调用 #registerFeignClient 进行客户端注册
for (BeanDefinition candidateComponent : candidateComponents) {
// 。。。省略N行
registerFeignClient(registry, annotationMetadata, attributes);
}
在 #registerFeignClient 方法中,则为每一个FeignClient创建 FeignClientFactoryBean
对象,FeignClientFactoryBean
实现 Spring FactoryBean
接口,因此实际创建 FeignClient 对象是在 FeignClientFactoryBean
的 #getObject 方法,也就是最终指向 #getTarget 如下:
public class FeignClientFactoryBean implements FactoryBean<Object> ... {
@Override
public Object getObject() {
return getTarget();
}
<T> T getTarget() {
FeignContext context = beanFactory != null ? beanFactory.getBean(FeignContext.class) : applicationContext.getBean(FeignContext.class);
// 关于 Builder 详见文章末尾
Feign.Builder builder = feign(context);
// 第1种返回方式
if (!StringUtils.hasText(url)) {
return (T) loadBalance(builder, context, new HardCodedTarget<>(type, name, url));
}
// 。。。省略N行,第2种返回方式
applyBuildCustomizers(context, builder);
Targeter targeter = get(context, Targeter.class);
return (T) targeter.target(this, builder, context, new HardCodedTarget<>(type, name, url));
}
}
判断 @FeignClient
中的 url 属性是否赋值,可以分为两种情况进行实例构建
- 方式1:未赋值则通过 #loadBalance 进行构建
- 方式2:如果url赋值,则根据URL为准,直接构建 FeignClient
常规开发中,一般使用 方式1 , #loadBalance 如下:
protected <T> T loadBalance(Feign.Builder builder, FeignContext context, HardCodedTarget<T> target) {
Client client = getOptional(context, Client.class);
if (client != null) {
builder.client(client);
applyBuildCustomizers(context, builder);
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-loadbalancer?");
}
targeter.target 再跟进去发现实际使用的是 Feign.Builder builder 的 #target 方法
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context,
Target.HardCodedTarget<T> target) {
return feign.target(target);
}
builder#target 如下:
public <T> T target(Target<T> target) {
return build().newInstance(target);
}
public Feign build() {
// 。。。省略N行
return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
}
再跟进去也就是 ReflectiveFeign#newInstance 方法,这个方法就是真正创建FeignClient代理对象的方法
@Override
public <T> T newInstance(Target<T> target) {
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;
}
创建 FeignClient Proxy 之后,实际上每一个方法都有一个 Handler,接口为:MethodHandler
,feign提供两个实现类,如下:
- SynchronousMethodHandler
- DefaultMethodHandler
在上面的代码中,if (Util.isDefault(method)) 成立,则使用 DefaultMethodHandler
,否则使用 nameToHandler.get 出来的 MethodHandler
,基本上是 SynchronousMethodHandler
,也有可能是如下实现:
// targetToHandlersByName.apply(target) 里面存在一个判断
if (md.isIgnored()) {
result.put(md.configKey(), args -> {
throw new IllegalStateException(md.configKey() + " is not a method handled by feign");
});
}
Util.isDefault:
public static boolean isDefault(Method method) {
// Default methods are public non-abstract, non-synthetic, and non-static instance methods
// declared in an interface.
// method.isDefault() is not sufficient for our usage as it does not check
// for synthetic methods. As a result, it picks up overridden methods as well as actual default
// methods.
final int SYNTHETIC = 0x00001000;
return ((method.getModifiers()
& (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC | SYNTHETIC)) == Modifier.PUBLIC)
&& method.getDeclaringClass().isInterface();
}
所以,最常见的处理器就是 SynchronousMethodHandler
处理器,它的 invoke 方法,就是真正执行 http 请求的方法,如下:
@Override
public Object invoke(Object[] argv) throws Throwable {
RequestTemplate template = buildTemplateFromArgs.create(argv);
Options options = findOptions(argv);
Retryer retryer = this.retryer.clone();
while (true) {
try {
return executeAndDecode(template, options);
} catch (RetryableException e) {
try {
retryer.continueOrPropagate(e);
} catch (RetryableException th) {
Throwable cause = th.getCause();
if (propagationPolicy == UNWRAP && cause != null) {
throw cause;
} else {
throw th;
}
}
if (logLevel != Logger.Level.NONE) {
logger.logRetry(metadata.configKey(), logLevel);
}
continue;
}
}
}
关于 Feign.Builder
从整体流程来看,最终FeignClient的构建都是通过 Feign.Builder 来处理,这个 Feign.Builder 本身就是用来构建 FeignClient 的,但是它还有几个子类:
- Spring Cloud OpenFeign 中,提供 FeignCircuitBreaker.Builder
- Spring Cloud Alibaba Sentinel 中,提供 SentinelFeign.Builder
FeignCircuitBreaker.Builder 则在 FeignClientsConfiguration
中进行配置,如下:
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(CircuitBreaker.class)
@ConditionalOnProperty("feign.circuitbreaker.enabled")
protected static class CircuitBreakerPresentFeignBuilderConfiguration {
@Bean
@Scope("prototype")
@ConditionalOnMissingBean({ Feign.Builder.class, CircuitBreakerFactory.class })
public Feign.Builder defaultFeignBuilder(Retryer retryer) {
return Feign.builder().retryer(retryer);
}
@Bean
@Scope("prototype")
@ConditionalOnMissingBean
@ConditionalOnBean(CircuitBreakerFactory.class)
public Feign.Builder circuitBreakerFeignBuilder() {
return FeignCircuitBreaker.builder();
}
}
SentinelFeign.Builder 则在 SentinelFeignAutoConfiguration
中进行配置,如下:
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ SphU.class, Feign.class })
public class SentinelFeignAutoConfiguration {
@Bean
@Scope("prototype")
@ConditionalOnMissingBean
@ConditionalOnProperty(name = "feign.sentinel.enabled")
public Feign.Builder feignSentinelBuilder() {
return SentinelFeign.builder();
}
}
所以这就解释了为什么Sentinel适配Feign时,需要配置 feign.sentinel.enabled=true