spring cloud feign
返回顶部
@EnableFeignClients
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({FeignClientsRegistrar.class})
public @interface EnableFeignClients {
String[] value() default {};
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
Class<?>[] defaultConfiguration() default {};
Class<?>[] clients() default {};
}
class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
private ResourceLoader resourceLoader;
private Environment environment;
public FeignClientsRegistrar() {
}
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
this.registerDefaultConfiguration(metadata, registry);//入口1
this.registerFeignClients(metadata, registry);//入口2
}
}
private void registerDefaultConfiguration(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
//将@EnableFeignClients的所有属性值导入map中
Map<String, Object> defaultAttrs = metadata
.getAnnotationAttributes(EnableFeignClients.class.getName(), true);
//如果@EnableFeignClients配置了defaultConfiguration,则往下运行。如果没有,rantion
//会使用默认的FeignConfiguration,一般我们这里不会设置这些配置,都是默认,但是如果设置了,
//就会好比我们自己写了@Configuration的类一样的效果,这里是自动配置了
if (defaultAttrs != null && defaultAttrs.containsKey("defaultConfiguration")) {
String name;
//如果原始类中有内部类,获取内部类名
if (metadata.hasEnclosingClass()) {
name = "default." + metadata.getEnclosingClassName();
}
//否则获取原始类名
else {
name = "default." + metadata.getClassName();
}
//注册@EnableFeignClients的Configuration配置
registerClientConfiguration(registry, name,
defaultAttrs.get("defaultConfiguration"));
}
}
public void registerFeignClients(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
//获取扫描器
ClassPathScanningCandidateComponentProvider scanner = getScanner();
scanner.setResourceLoader(this.resourceLoader);
Set<String> basePackages;
//将@EnableFeignClients的所有自定义配置属性放入内存map中
Map<String, Object> attrs = metadata
.getAnnotationAttributes(EnableFeignClients.class.getName());
//初始化一个@FeignClient的标签类型过滤器
AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(
FeignClient.class);
//如果设置了@EnableFeignClients的自定义配置,获取clients配置项中的Class数组
final Class<?>[] clients = attrs == null ? null
: (Class<?>[]) attrs.get("clients");
//如果没有自定义配置
if (clients == null || clients.length == 0) {
//扫描器添加标签过滤类型
scanner.addIncludeFilter(annotationTypeFilter);
//获取默认配置扫描包集合
basePackages = getBasePackages(metadata);
}
else { //如果有自定义配置
final Set<String> clientClasses = new HashSet<>();
basePackages = new HashSet<>();
//遍历配置的每一个client Class
for (Class<?> clazz : clients) {
//添加每一个client Class的包
basePackages.add(ClassUtils.getPackageName(clazz));
//添加每一个client Class的类名(包含内部类名)
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)));
}
//遍历扫描包集合
for (String basePackage : basePackages) {
//用扫描器扫描包,获取bean集合
Set<BeanDefinition> candidateComponents = scanner
.findCandidateComponents(basePackage);
//遍历扫描到的bean集合
for (BeanDefinition candidateComponent : candidateComponents) {
//如果该bean为一个标签定义的bean
if (candidateComponent instanceof AnnotatedBeanDefinition) {
AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
//获取该bean的元数据
AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
//断言该bean为一个接口(Interface)
Assert.isTrue(annotationMetadata.isInterface(),
"@FeignClient can only be specified on an interface");
//获取@FeignClient的所有属性放入map中
Map<String, Object> attributes = annotationMetadata
.getAnnotationAttributes(
FeignClient.class.getCanonicalName());
//获取@FeignClient配置的name(name或者value或者serviceId必须配置一个,并取其一)
String name = getClientName(attributes);
//注册单个@FeignClient的Configuration配置
registerClientConfiguration(registry, name,
attributes.get("configuration"));
//注册@FeignClient定义的bean
registerFeignClient(registry, annotationMetadata, attributes);//入口
}
}
}
}
- 实例化Feign的配置类
- 扫描所有@FeignClient注解的接口中的方法,通过registerFeignClient方法进行注册
继续看下【通过registerFeignClient方法进行注册】
private void registerFeignClient(BeanDefinitionRegistry registry,
AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
//获取被@FeignClient标签注解的类名称,这里是接口名
String className = annotationMetadata.getClassName();
//设置bean建造器的bean工厂
BeanDefinitionBuilder definition = BeanDefinitionBuilder
.genericBeanDefinition(FeignClientFactoryBean.class);//入口
//断言@FeignClient配置的fallback,fallbackFactory必须为接口
validate(attributes);
//建造器添加@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);
String alias = name + "FeignClient";
//使用该建造器建造bean
AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
//获取主bean标识
boolean primary = (Boolean)attributes.get("primary"); // has a default, won't be null
//设置该bean是否为主bean
beanDefinition.setPrimary(primary);
//通过@FeignClient设置的限定符属性获取别名
String qualifier = getQualifier(attributes);
if (StringUtils.hasText(qualifier)) {
alias = qualifier;
}
//初始化一个bean的类名、别名解析器
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,
new String[] { alias });
//通过bean工厂和别名解析器,将该bean注册到spring容器中
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
}
- 先定义了bean的工厂类FeignClientFactoryBean,通过这个工厂的getObject获取bean
- 将bean注册到spring容器
看一下【通过这个工厂的getObject获取bean】
public Object getObject() throws Exception {
//直接调用了getTarget()方法
return getTarget();
}
/**
* @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() {
//这个FeignContext在FeignAutoConfiguration配置中已经声明了,所以可以直接用applicationContext获取bean
FeignContext context = applicationContext.getBean(FeignContext.class);
//配置feign 的decoder、encoder、retryer、contract、RequestInterceptor等
//这些有默认配置,在FeignAutoConfiguration及FeignClientsConfiguration中有默认配置
Feign.Builder builder = feign(context);
if (!StringUtils.hasText(this.url)) {
//如果@FeignClient注解上指定了url,其实除非本地调试,一般不建议指定URL
String url;
if (!this.name.startsWith("http")) {
url = "http://" + this.name;
}
else {
url = this.name;
}
//处理URL,没配置URL时,这里的URL形式为http://name+/path
url += cleanPath();
//使用负载均衡处理feign 请求
return (T) loadBalance(builder, context, new HardCodedTarget<>(this.type,
this.name, url));
}
//配置了FeignClient的具体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 load 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 (T) targeter.target(this, builder, context, new HardCodedTarget<>(
this.type, this.name, url));
}
- 获取FeignContext,通过FeignContext配置feign的decoder、encoder、retryer、contract、RequestInterceptor等
- decoder:将http请求的response转换成对象
- encoder:将http请求的对象转换成http request body
- contract:校验Feign Client上的注解及value值是否合法
- retryer:定义http请求如果失败了是否应该重试以及重试间隔、方式等等
- RequestInterceptor:feign发起请求前的拦截器,可以全局定义basic auth、发起请求前自动添加header等等
- 如果@FeignClient注解上指定了url,其实除非本地调试,一般不建议指定URL,直接通过url请求
- 如果@FeignClient注解上未指定了url,通过loadBalance方法负载均衡的方式请求
【通过loadBalance方法负载均衡的方式请求】
protected <T> T loadBalance(Feign.Builder builder, FeignContext context,
HardCodedTarget<T> target) {
//默认client为LoadBalancerFeignClient,为啥?参见DefaultFeignLoadBalancedConfiguration
Client client = getOptional(context, Client.class);
if (client != null) {
builder.client(client);
//这个Targeter默认为DefaultTargeter,参见FeignAutoConfiguration
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?");
}
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context,
Target.HardCodedTarget<T> target) {
return feign.target(target);
}
public <T> T target(Target<T> target) {
return build().newInstance(target);
}
//ReflectiveFeign
public <T> T newInstance(Target<T> target) {
//这个apply方法就是ReflectiveFeign中的apply方法,返回了每个方法的调用包装类SynchronousMethodHandler
Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();
List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>();
//这个target.type()返回的就是声明@FeignClient注解所在的class
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)));
}
}
//返回了ReflectiveFeign.FeignInvocationHandler对象,这个对象的invoke方法其实就是调用了SynchronousMethodHandler.invoke方法
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;
}
public Map<String, MethodHandler> apply(Target key) {
//获取类上的方法的元数据,如返回值类型,参数类型,注解数据等等
List<MethodMetadata> metadata = contract.parseAndValidatateMetadata(key.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);
} else if (md.bodyIndex() != null) {
buildTemplate = new BuildEncodedTemplateFromArgs(md, encoder, queryMapEncoder);
} else {
buildTemplate = new BuildTemplateByResolvingArgs(md, queryMapEncoder);
}
//这个factory是SynchronousMethodHandler.Factory,create方法返回了一个SynchronousMethodHandler对象
result.put(md.configKey(),
factory.create(key, md, buildTemplate, options, decoder, errorDecoder));
}
return result;
}
- 注入的其实是Targeter类,Targetr类包装了FeignCLient的proxy,proxy内部绑定了methodHandler为SynchronousMethodHandler
执行过程
因为是通过jdk的动态代理类执行,所以会执行到自定义拦截器FeignInvocationHandler的invoke方法
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();
}
//除了equals、hashCode、toString方法外,其他方法都走dispatch.get(method).invoke(args)方法。
//点击这个方法的实现类,就可以追到 SynchronousMethodHandler的invoke方法了。
return dispatch.get(method).invoke(args);
}
public Object invoke(Object[] argv) throws Throwable {
//根据调用参数创建一个RequestTemplate,用来具体处理http调用请求
RequestTemplate template = buildTemplateFromArgs.create(argv);
//克隆出一个一模一样的Retryer,用来处理调用失败后的重试
Retryer retryer = this.retryer.clone();
while (true) {
try {
//发送http request以及处理response等
return executeAndDecode(template);
} catch (RetryableException e) {
//处理重试次数、重试间隔等等
retryer.continueOrPropagate(e);
continue;
}
}
}
- 通过create创建RequestTemplate
- 调用executeAndDecode
【通过create创建RequestTemplate】
//ReflectiveFeign.BuildTemplateByResolvingArgs
public RequestTemplate create(Object[] argv) {
//获取methodMetada的template,这个RequestTemplate是可变的,跟随每次调用参数而变。
RequestTemplate mutable = new RequestTemplate(metadata.template());
if (metadata.urlIndex() != null) {
//处理@PathVariable在URL上插入的参数
int urlIndex = metadata.urlIndex();
checkArgument(argv[urlIndex] != null, "URI parameter %s was null", urlIndex);
mutable.insert(0, String.valueOf(argv[urlIndex]));
}
//处理调用方法的param参数,追加到URL ?后面的参数
Map<String, Object> varBuilder = new LinkedHashMap<String, Object>();
for (Entry<Integer, Collection<String>> entry : metadata.indexToName().entrySet()) {
int i = entry.getKey();
Object value = argv[entry.getKey()];
if (value != null) { // Null values are skipped.
if (indexToExpander.containsKey(i)) {
value = expandElements(indexToExpander.get(i), value);
}
for (String name : entry.getValue()) {
varBuilder.put(name, value);
}
}
}
//处理query参数以及body内容
RequestTemplate template = resolve(argv, mutable, varBuilder);
if (metadata.queryMapIndex() != null) {
// add query map parameters after initial resolve so that they take
// precedence over any predefined values
//当 RequestTemplate处理完参数后,再处理@QueryMap注入的参数,以便优先于任意值。
Object value = argv[metadata.queryMapIndex()];
Map<String, Object> queryMap = toQueryMap(value);
template = addQueryMapQueryParameters(queryMap, template);
}
if (metadata.headerMapIndex() != null) {
//处理RequestTemplate的header内容
template = addHeaderMapHeaders((Map<String, Object>) argv[metadata.headerMapIndex()], template);
}
return template;
}
根据调用时的参数等构造了RequestTemplate的param、body、header等内容。
【调用executeAndDecode】
//SynchronousMethodHandler
Object executeAndDecode(RequestTemplate template) throws Throwable {
//构造Request,将RequestTemplate中的参数等放入Request中
Request request = targetRequest(template);
Response response;
try {
//这个client默认实现是Client接口中的Defalut,实现是通过HttpURLConnection发送请求
//另一种是LoadBalancerFeignClient,默认也是Client接口中的Defalut,可以通过配置指定为Apache的HTTPClient,也可以指定为OKhttp来发送请求,在每个具体实现中来通过ribbon实现负载均衡,负载到集群中不同的机器,这里不再发散
response = client.execute(request, options);//入口
// ensure the request is set. TODO: remove in Feign 10
response.toBuilder().request(request).build();
} catch (IOException e) {
throw errorExecuting(request, e);
}
boolean shouldClose = true;
try {
//处理response的返回值
if (Response.class == metadata.returnType()) {
if (response.body() == null) {
return response;
}
// Ensure the response body is disconnected
byte[] bodyData = Util.toByteArray(response.body().asInputStream());
return response.toBuilder().body(bodyData).build();
}
//根据状态码处理下response
if (response.status() >= 200 && response.status() < 300) {
if (void.class == metadata.returnType()) {
return null;
} else {
Object result = decode(response);
shouldClose = closeAfterDecode;
return result;
}
} else if (decode404 && response.status() == 404 && void.class != metadata.returnType()) {
Object result = decode(response);
shouldClose = closeAfterDecode;
return result;
} else {
throw errorDecoder.decode(metadata.configKey(), response);
}
}
}
//LoadBalancerFeignClient
@Override
public Response execute(Request request, Request.Options options) throws IOException {
try {
URI asUri = URI.create(request.url());
String clientName = asUri.getHost();
URI uriWithoutHost = cleanUrl(request.url(), clientName);
FeignLoadBalancer.RibbonRequest ribbonRequest = new FeignLoadBalancer.RibbonRequest(
this.delegate, request, uriWithoutHost);
IClientConfig requestConfig = getClientConfig(options, clientName);
return lbClient(clientName).executeWithLoadBalancer(ribbonRequest,
requestConfig).toResponse();//入口
}
catch (ClientException e) {
IOException io = findIOException(e);
if (io != null) {
throw io;
}
throw new RuntimeException(e);
}
}
//AbstractLoadBalancerAwareClient
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 {
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 {
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);
}
}
}
public Observable<T> submit(final ServerOperation<T> operation) {
//入口
//创建Observable
//selectServer方法选择server
Observable<T> o = (this.server == null ? this.selectServer() : Observable.just(this.server)).concatMap(new Func1<Server, Observable<T>>() {
public Observable<T> call(Server server) {
context.setServer(server);
final ServerStats stats = LoadBalancerCommand.this.loadBalancerContext.getServerStats(server);
Observable<T> o = Observable.just(server).concatMap(new Func1<Server, Observable<T>>() {
public Observable<T> call(final Server server) {
//内部代码省略
}
});
if (maxRetrysSame > 0) {
o = o.retry(LoadBalancerCommand.this.retryPolicy(maxRetrysSame, true));
}
return o;
}
});
if (maxRetrysNext > 0 && this.server == null) {
o = o.retry(this.retryPolicy(maxRetrysNext, false));
}
return;
}
private Observable<Server> selectServer() {
return Observable.create(new OnSubscribe<Server>() {
@Override
public void call(Subscriber<? super Server> next) {
try {
Server server = loadBalancerContext.getServerFromLoadBalancer(loadBalancerURI, loadBalancerKey);
next.onNext(server);
next.onCompleted();
} catch (Exception e) {
next.onError(e);
}
}
});
}