您的位置:首页 > 编程语言 > Java开发

SpringCloud Feign源码解析

2020-07-15 05:20 204 查看

结论

@EnableFeignClients注解将类FeignClientsRegistrar注册到Spring中

FeignClientsRegistrar类主要是扫描包路径下的所有类,将带有@FeignClient注解的类或接口注册到Spring中

如何注册带有@FeignClient的类或接口呢?就是生成一个BeanDefinitionHolder类,beanName为@FeignClient所在接口的名称,beanDefinition为FeignClientFactoryBean,并将@FeignClient的属性添加到FeignClientFactoryBean中

至此,我们已经把带有@FeignClient注解的类或接口注册到Spring中

FeignClientFactoryBean.getObject()方法返回的是一个代理类,InvocationHandler中包含类中每个方法对应的MethodHandler,也就是SynchronousMethodHandler,方法真正执行就是SynchronousMethodHandler.invoke()方法

LoadBalancerFeignClient.execute()方法进行业务的处理,在这一步操作中就用到了ribbon和Hystrix功能

1. 分析注解@EnableFeignClients

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)// 重点在这里,注入FeignClientsRegistrar类
public @interface EnableFeignClients {

}

2. FeignClientsRegistrar.java分析

通过其类结构可知,其实现了ImportBeanDefinitionRegistrar接口,那么在registerBeanDefinitions()中就会注册一些bean到Spring中

class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar,
ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware{

@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
// 1.针对那些在@EnableFeignClients中添加了defaultConfiguration属性的进行操作
// 将这些类定义的bean添加到容器中
registerDefaultConfiguration(metadata, registry);

// 2.注册那些添加了@FeignClient的类或接口
// 重点就在这里
registerFeignClients(metadata, registry);
}
}

3. registerFeignClients(metadata, registry)方法分析

public void registerFeignClients(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
ClassPathScanningCandidateComponentProvider scanner = getScanner();
scanner.setResourceLoader(this.resourceLoader);

// 1.以下代码的主要功能是扫描包下的所有带有@FeignClient注解的类
Set<String> basePackages;

Map<String, Object> attrs = metadata
.getAnnotationAttributes(EnableFeignClients.class.getName());
// @FeignClient注解过滤器
AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(
FeignClient.class);
final Class<?>[] clients = attrs == null ? null
: (Class<?>[]) attrs.get("clients");
if (clients == null || clients.length == 0) {
// 在这里获取带有@FeignClient注解的类,放在basePackages中
scanner.addIncludeFilter(annotationTypeFilter);
basePackages = getBasePackages(metadata);
}
else {
final Set<String> clientClasses = new HashSet<>();
basePackages = new HashSet<>();
for (Class<?> clazz : clients) {
basePackages.add(ClassUtils.getPackageName(clazz));
clientClasses.add(clazz.getCanonicalName());
}
AbstractClassTestingTypeFilter filter = new AbstractClassTestingTypeFilter() {
@Override
protected boolean match(ClassMetadata metadata) {
String cleaned = metadata.getClassName().replaceAll("\\$", ".");
return clientClasses.contains(cleaned);
}
};
scanner.addIncludeFilter(
new AllTypeFilter(Arrays.asList(filter, annotationTypeFilter)));
}

// 2.针对所有带有@FeignClient注解的类或接口分别封装
// 注册其Configuration类(如果有的话)
// 并将类或接口本身注入到Spring中
for (String basePackage : basePackages) {
Set<BeanDefinition> candidateComponents = scanner
.findCandidateComponents(basePackage);
for (BeanDefinition candidateComponent : candidateComponents) {
if (candidateComponent instanceof AnnotatedBeanDefinition) {
// verify annotated class is an interface
AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
Assert.isTrue(annotationMetadata.isInterface(),
"@FeignClient can only be specified on an interface");

Map<String, Object> attributes = annotationMetadata
.getAnnotationAttributes(
FeignClient.class.getCanonicalName());

String name = getClientName(attributes);
// 2.1 注册其Configuration类(如果有的话)
// 本例中使用的是默认的Configuration,就不再分析该段代码
registerClientConfiguration(registry, name,
attributes.get("configuration"));

// 2.2 并将类或接口本身注入到Spring中
registerFeignClient(registry, annotationMetadata, attributes);
}
}
}
}

4.registerFeignClient()方法的分析

private void registerFeignClient(BeanDefinitionRegistry registry,
AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
// 1.获取类名称,也就是本例中的FeignService接口
String className = annotationMetadata.getClassName();

// 2.BeanDefinitionBuilder的主要作用就是构建一个AbstractBeanDefinition
// AbstractBeanDefinition类最终被构建成一个BeanDefinitionHolder
// 然后注册到Spring中
// 注意:beanDefinition类为FeignClientFactoryBean,故在Spring获取类的时候实际返回的是
// FeignClientFactoryBean类
BeanDefinitionBuilder definition = BeanDefinitionBuilder
.genericBeanDefinition(FeignClientFactoryBean.class);
validate(attributes);

// 3.添加FeignClientFactoryBean的属性,
// 这些属性也都是我们在@FeignClient中定义的属性
definition.addPropertyValue("url", getUrl(attributes));
definition.addPropertyValue("path", getPath(attributes));
String name = getName(attributes);
definition.addPropertyValue("name", name);
definition.addPropertyValue("type", className);
definition.addPropertyValue("decode404", attributes.get("decode404"));
definition.addPropertyValue("fallback", attributes.get("fallback"));
definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);

// 4.设置别名 name就是我们在@FeignClient中定义的name属性
String alias = name + "FeignClient";
AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();

boolean primary = (Boolean)attributes.get("primary"); // has a default, won't be null

beanDefinition.setPrimary(primary);

String qualifier = getQualifier(attributes);
if (StringUtils.hasText(qualifier)) {
alias = qualifier;
}

// 5.定义BeanDefinitionHolder,
// 在本例中 名称为FeignService,类为FeignClientFactoryBean
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,
new String[] { alias });
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
}

通过分析可知:我们最终是向Spring中注册了一个bean,bean的名称就是类或接口的名称(也就是本例中的FeignService),bean的实现类是FeignClientFactoryBean,其属性设置就是我们在@FeignClient中定义的属性

那么下面我们在Controller中对FeignService的的引入,实际就是引入了FeignClientFactoryBean类

5.FeignClientFactoryBean的分析

其实现了FactoryBean接口,那么当从ApplicationContext中获取该bean的时候,实际调用的是其getObject()方法

class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean,
ApplicationContextAware{

public Object getObject() throws Exception {
// 1.获取容器中的FeignContext实现
// 默认实现在FeignAutoConfiguration类中
FeignContext context = applicationContext.getBean(FeignContext.class);
// 2.主要使用构造者模式来构建一个Feign
// 在1)中详细分析
Feign.Builder builder = feign(context);

// 3.本例中没有指定URL,故执行if
if (!StringUtils.hasText(this.url)) {
String url;
if (!this.name.startsWith("http")) {
url = "http://" + this.name;
}
else {
url = this.name;
}
url += cleanPath();
// 4.关键方法
// 在2)中详细分析
return loadBalance(builder, context, new HardCodedTarget<>(this.type,
this.name, 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) {
// not lod 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));
}
}

5.1.feign(context)构造者模式构建Feign.Builder

protected Feign.Builder feign(FeignContext context) {
FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);
Logger logger = loggerFactory.create(this.type);

// @formatter:off
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));
// @formatter:on

// 下面的几项getOptional()主要功能就是从ApplicationContext中获取对应类的实现
// 这些类用户可自定义,默认的话是从FeignAutoConfiguration中获取对应bean
Logger.Level level = getOptional(context, Logger.Level.class);
if (level != null) {
builder.logLevel(level);
}
Retryer retryer = getOptional(context, Retryer.class);
if (retryer != null) {
builder.retryer(retryer);
}
ErrorDecoder errorDecoder = getOptional(context, ErrorDecoder.class);
if (errorDecoder != null) {
builder.errorDecoder(errorDecoder);
}
Request.Options options = getOptional(context, Request.Options.class);
if (options != null) {
builder.options(options);
}
Map<String, RequestInterceptor> requestInterceptors = context.getInstances(
this.name, RequestInterceptor.class);
if (requestInterceptors != null) {
builder.requestInterceptors(requestInterceptors.values());
}

if (decode404) {
builder.decode404();
}

return builder;
}

5.2 loadBalance(builder, context, new HardCodedTarget<>(this.type,this.name, url))获取负载均衡后的对象

protected <T> T loadBalance(Feign.Builder builder, FeignContext context,
HardCodedTarget<T> target) {
// 1.获取Client的实现类,默认为LoadBalancerFeignClient类
// 实现在FeignRibbonClientAutoConfiguration中
Client client = getOptional(context, Client.class);
if (client != null) {
// 2.将LoadBalancerFeignClient包装到Feign.Builder
builder.client(client);

// 3.获取ApplicationContext中的Targeter实现
// 默认实现为HystrixTargeter,实现在FeignAutoConfiguration类中
Targeter targeter = get(context, Targeter.class);

// 4.重点在这里
// 我们来看下这个方法
return targeter.target(this, builder, context, target);
}
...
}

// HystrixTargeter.target()
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context,
Target.HardCodedTarget<T> target) {
// Feign.Builder为feign包路径下,不是 feign.hystrix.HystrixFeign.Builder,故直接走return方法
if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) {
// 我们来看下这个方法,在feign.Feign.Builder类中
return feign.target(target);
}
...
}

// feign.Feign.Builder.target(target)
public <T> T target(Target<T> target) {
return build().newInstance(target);
}

// feign.Feign.Builder.build()
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
return new ReflectiveFeign(handlersByName, invocationHandlerFactory);
}

// ReflectiveFeign.newInstance(target)
public <T> T newInstance(Target<T> target) {
// 1.分析出具体方法和对应的Handler处理,
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)));
}
}
// 2.由factory创建一个InvocationHandler,实现为FeignInvocationHandler
// 可知其代理的target为HardCodedTarget
InvocationHandler handler = factory.create(target, methodToHandler);
// 3.可以看到最终返回的是一个代理
T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(), new Class<?>[]{target.type()}, handler);

for(DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
defaultMethodHandler.bindTo(proxy);
}
return proxy;
}

由以上分析可知,FeignClientFactoryBean.getObject()具体返回的是一个代理类,具体为FeignInvocationHandler

6. FeignInvocationHandler接收请求方法过程分析

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("equals".equals(method.getName())) {
try {
Object
otherHandler =
args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;
return equals(otherHandler);
} catch (IllegalArgumentException e) {
return false;
}
} else if ("hashCode".equals(method.getName())) {
return hashCode();
} else if ("toString".equals(method.getName())) {
return toString();
}
// 非Object方法,则默认执行该句
// dispatch为map,方法的实现类为SynchronousMethodHandler
// 我们来分析SynchronousMethodHandler.invoke()方法
return dispatch.get(method).invoke(args);
}

6.1 SynchronousMethodHandler.invoke()

public Object invoke(Object[] argv) throws Throwable {
// 1.根据请求参数创建一个feign.RequestTemplate
RequestTemplate template = buildTemplateFromArgs.create(argv);
// 2.用户定义的重试策略
Retryer retryer = this.retryer.clone();
while (true) {
try {
// 重要方法在这里
return executeAndDecode(template);
} catch (RetryableException e) {
retryer.continueOrPropagate(e);
if (logLevel != Logger.Level.NONE) {
logger.logRetry(metadata.configKey(), logLevel);
}
continue;
}
}
}

6.2 executeAndDecode(template)执行请求

Object executeAndDecode(RequestTemplate template) throws Throwable {
// 1.封装请求信息,feign.Request,会将请求封装为以下信息
// GET http://part-1-sms-interface/sms/test HTTP/1.1
Request request = targetRequest(template);

if (logLevel != Logger.Level.NONE) {
logger.logRequest(metadata.configKey(), logLevel, request);
}

Response response;
long start = System.nanoTime();
try {
// 2.真正的执行在这里
// client为LoadBalancerFeignClient
// 继续在6.3中详细分析
response = client.execute(request, options);
// ensure the request is set. TODO: remove in Feign 10
response.toBuilder().request(request).build();
} catch (IOException e) {
if (logLevel != Logger.Level.NONE) {
logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime(start));
}
throw errorExecuting(request, e);
}
long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);

// 响应处理
...
}

6.3.LoadBalancerFeignClient.execute(request, options)请求负载均衡

public Response execute(Request request, Request.Options options) throws IOException {
try {
// 1.获取URI
URI asUri = URI.create(request.url());
String clientName = asUri.getHost();
URI uriWithoutHost = cleanUrl(request.url(), clientName);

// 2.封装成RibbonRequest请求
FeignLoadBalancer.RibbonRequest ribbonRequest = new FeignLoadBalancer.RibbonRequest(
this.delegate, request, uriWithoutHost);

// 3.封装请求参数信息
IClientConfig requestConfig = getClientConfig(options, clientName);

// 4.执行请求,并进行负载均衡
// 本方法可分为三步:
// 1)lbClient(clientName)获取执行类,本例中为FeignLoadBalancer
// 2)FeignLoadBalancer.executeWithLoadBalancer()执行请求
// 3)toResponse()获取响应
return lbClient(clientName).executeWithLoadBalancer(ribbonRequest,
requestConfig).toResponse();
}
catch (ClientException e) {
IOException io = findIOException(e);
if (io != null) {
throw io;
}
throw new RuntimeException(e);
}
}

6.4 FeignLoadBalancer.executeWithLoadBalancer()执行请求

public T executeWithLoadBalancer(final S request, final IClientConfig requestConfig) throws ClientException {
RequestSpecificRetryHandler handler = getRequestSpecificRetryHandler(request, requestConfig);
LoadBalancerCommand<T> command = LoadBalancerCommand.<T>builder()
.withLoadBalancerContext(this)
.withRetryHandler(handler)
.withLoadBalancerURI(request.getUri())
.build();

try {
// 在这里可以看到Hystrix的相关代码,
return command.submit(
new ServerOperation<T>() {
@Override
public Observable<T> call(Server server) {
URI finalUri = reconstructURIWithServer(server, request.getUri());
S requestForServer = (S) request.replaceUri(finalUri);
try {
// 执行ribbon负载均衡请求
return Observable.just(AbstractLoadBalancerAwareClient.this.execute(requestForServer, requestConfig));
}
catch (Exception e) {
return Observable.error(e);
}
}
})
.toBlocking()
.single();
} catch (Exception e) {
Throwable t = e.getCause();
if (t instanceof ClientException) {
throw (ClientException) t;
} else {
throw new ClientException(e);
}
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: